
Opencv图像操作——图像遍历、图像ROI选取、图像混合
发布日期:2021-05-08 07:47:32
浏览次数:24
分类:原创文章
本文共 10305 字,大约阅读时间需要 34 分钟。
文章目录
前言
Opencv图像操作与混合,用opencv实现对图像的修改
一、图像是什么?
在这一篇文章中,我们对图像已经有了一定的了解
https://blog.csdn.net/ivan_9/article/details/113059961
二、OpenCV中数据类型和常用数据类型对应
数据类型 | opencv数据类型对应 |
---|---|
Mat<uchar> | CV_8U |
Mat<char> | CV_8S |
Mat<ushort> | CV_16U |
Mar<short> | CV_16S |
Mat<int> | CV_32S |
Mat<float> | CV_32F |
Mat<double> | CV_16F |
三、图像的操作
1)imread函数:利用imread函数读取图像
imread是image read的缩写:即负责图像读取
3.1.1、利用imread实现读取的代码块:
Mat src, gray_src;src = imread("C:\\Users\\ASUS\\Desktop\\1.jpg");
3.1.2、imread函数在opencv里的定义:
CV_EXPORTS_W Mat imread( const String& filename, int flags = IMREAD_COLOR );/** @brief Loads a multi-page image from a file.The function imreadmulti loads a multi-page image from the specified file into a vector of Mat objects.@param filename Name of file to be loaded.@param flags Flag that can take values of cv::ImreadModes, default with cv::IMREAD_ANYCOLOR.@param mats A vector of Mat objects holding each page, if more than one.@sa cv::imread*/
2)imwrite函数:利用imwrite函数写入图像,即保存图像
imwrite是image write的缩写:即负责图像写入
3.2.1、利用imwrite实现写入的代码块:
imwrite("C:\\Users\\ASUS\\Desktop\\imwrite.jpg", src);
3.2.2、imwrite函数在opencv里的定义:
CV_EXPORTS_W bool imwrite( const String& filename, InputArray img, const std::vector<int>& params = std::vector<int>());/// @overload multi-image overload for bindings//filename:需要写入的文件名,会自己创建(像imwrite("imwrite.jpg",src);支持JPEG,PNG,PPM,PGM,PBM,TIFF等格式//img:要保存的图像//params:表示为特定格式保存的参数编码
3)遍历图像
3.3.1、利用at函数实现单通道图像遍历,对图像像素点进行操作:
代码块
#include <opencv2/opencv.hpp>#include <iostream>using namespace std;using namespace cv;int main() { Mat src, gray_src; src = imread("C:\\Users\\ASUS\\Desktop\\1.jpg"); if (!src.data) { cout << "could not load your image!"; return 0; } namedWindow("input_image", WINDOW_AUTOSIZE); imshow("input_image", src); namedWindow("output_image", WINDOW_AUTOSIZE); cvtColor(src, gray_src, COLOR_BGR2GRAY); //利用色彩空间转换函数,转化为灰度图像,灰度图像只有单通道 int height = gray_src.rows; int width = gray_src.cols; //单通道 for (int row = 0; row < height; row++) { for (int col = 0; col < width; col++) { int gray = gray_src.at<uchar>(row, col); gray_src.at<uchar>(row, col) = 255 - gray; } } imshow("gray_invert", gray_src); waitKey(0); return 0;}
利用at函数,单通道遍历图像后的运行结果:
3.3.2、利用at实现多通道图像遍历:
代码块:
#include <opencv2/opencv.hpp>#include <iostream>using namespace std;using namespace cv;int main() { Mat src, dst; src = imread("C:\\Users\\ASUS\\Desktop\\1.jpg"); if (!src.data) { cout << "could not load your image!"; return 0; } namedWindow("input_image", WINDOW_AUTOSIZE); imshow("input_image", src); namedWindow("output_image", WINDOW_AUTOSIZE); int height = src.rows; int width = src.cols; dst.create(src.size(), src.type()); height = src.rows; width = src.cols; int nc = src.channels(); for (int row = 0; row < height; row++) { for (int col = 0; col < width; col++) { if (nc == 1) { //单通道 int One = src.at<uchar>(row, col); src.at<uchar>(row, col) = 255 - One; } else if (nc == 3) { //多通道 int b = src.at<Vec3b>(row, col)[0]; int g = src.at<Vec3b>(row, col)[1]; int r = src.at<Vec3b>(row, col)[2]; dst.at<Vec3b>(row, col)[0] = 255 - b; dst.at<Vec3b>(row, col)[1] = 255 - g; dst.at<Vec3b>(row, col)[2] = 255 - r; }//Vec3b放着bgr的像素,每个像素的读法采用Vec3b;Vec3f是浮点型的像素 } } imshow("output_image", dst); waitKey(0); return 0;}
利用at函数,多通道遍历图像后的运行结果:
3.3.3、利用at函数以及随机函数生成一张图片:
代码块:
#include <iostream>#include <opencv2/opencv.hpp>using namespace std;using namespace cv;int main() { Mat src; src = Mat(666, 666, CV_8UC3); int height = src.rows; int weight = src.cols; for (int row = 0; row < height; row++){ for (int col = 0; col < weight; col++) { src.at<Vec3b>(row, col)[0] = rand() * 255 + 1;//让随机数处于0-255之间,也可以rand() % 255 src.at<Vec3b>(row, col)[1] = rand() * 255 + 1; src.at<Vec3b>(row, col)[2] = rand() * 255 + 1; } } namedWindow("my_random_image", WINDOW_AUTOSIZE); imshow("my_random_image", src); waitKey(6000); //图像停滞6秒后消失; return 0;}
运行结果:
3.3.4、ptr指针遍历图像:
代码块:
#include <iostream>#include <opencv2/opencv.hpp>using namespace std;using namespace cv;int main() { Mat src; src = imread("C:\\Users\\ASUS\\Desktop\\2.jpg"); if (!src.data) { cout << "could not load image..." << endl; return 0; } namedWindow("init_image", WINDOW_AUTOSIZE); imshow("init_image", src); int height = src.rows; int weight = src.cols; int chan = src.channels(); for (int row = 0; row < height; row++) { uchar* row_Pointer = src.ptr<uchar>(row); for (int col = 0; col < weight * chan; col++) { //图像是三通道的,所以要*3 row_Pointer[col] = saturate_cast<uchar>(row_Pointer[col] + 66); //在原有图像的基础上,每个像素点加66 } } namedWindow("changed_image", WINDOW_AUTOSIZE); imshow("changed_image", src); waitKey(6666); //图像停滞6.666秒后消失; return 0;}
运行结果:
3.3.5、iterator迭代器遍历图像:
代码块:
#include <iostream>#include <opencv2/opencv.hpp>using namespace std;using namespace cv;int main() { Mat src; src = imread("C:\\Users\\ASUS\\Desktop\\2.jpg"); if (!src.data) { cout << "could not load image..." << endl; return 0; } namedWindow("init_image", WINDOW_AUTOSIZE); imshow("init_image", src); for (Mat_<Vec3b>::iterator iter = src.begin<Vec3b>(); iter != src.end<Vec3b>(); iter++) { //利用迭代器遍历图像,对三通道依次进行修改 (*iter)[0] = saturate_cast<uchar>((*iter)[0] + 1); (*iter)[1] = saturate_cast<uchar>((*iter)[1] + 111); (*iter)[2] = saturate_cast<uchar>((*iter)[2] + 1); //使用saturate_cast<uchar>()函数,防止溢出 } namedWindow("changed_image", WINDOW_AUTOSIZE); imshow("changed_image", src); waitKey(6666); //图像停滞6.666秒后消失; return 0;}
运行结果:
3.3.6、iterator迭代器遍历图像:
4)ROI区域
3.4.1、ROI区域的定义:
- ROI全称region of interest. 在图像处理领域,感兴趣区域(ROI) 是从图像中选择一块图像区域,该区域是图像分析所关注的重点。
- 圈定该区域以便进行进一步处理。
- 使用ROI圈定你想读的目标,可以减少处理时间,增加精度。
3.4.2、规则的ROI区域选取:
(A) 使用Rect函数,截取ROI区域:
程序代码:
#include <iostream>#include <opencv2/opencv.hpp>using namespace std;using namespace cv;int main() { Mat src; src = imread("C:\\Users\\ASUS\\Desktop\\2.jpg"); if (src.empty()) { cout << "could not load your image..."; return 0; } namedWindow("init_image", WINDOW_AUTOSIZE); imshow("init_image", src); Mat dst = src(Rect(150, 50, 150, 150)); //Rect 四个参数分别为x,y,截取多长的x,截取多长的y namedWindow("rect_image", WINDOW_AUTOSIZE); imshow("rect_image", dst); waitKey(0); return 0;}
运行结果:
(B) 使用Range函数,截取ROI区域:
解析:
- Mat(Range(定位x,宽度), Range(定义y,长度));
- 用Range::all()静态方法来获取所有的行或列
程序代码:
#include <iostream>#include <opencv2/opencv.hpp>using namespace std;using namespace cv;int main() { Mat src; src = imread("C:\\Users\\ASUS\\Desktop\\1.jpg"); if (src.empty()) { cout << "could not load your image..."; return 0; } namedWindow("init_image", WINDOW_AUTOSIZE); imshow("init_image", src); Mat dst = src(Range(150, 350), Range(100,400)); /*Mat::operator()( Range _rowRange, Range _colRange ) const{ return Mat(*this, _rowRange, _colRange);} 利用Mat 的方法提取ROI区域 */ namedWindow("rect_image", WINDOW_AUTOSIZE); imshow("rect_image", dst); waitKey(0); return 0;}
运行结果:
3.4.3、不规则的ROI区域选取:
程序代码:
#include <iostream>#include <opencv2/opencv.hpp>using namespace std;using namespace cv;int main() { Mat src, dst, mask; src = imread("C:\\Users\\ASUS\\Desktop\\3.png"); if (src.empty()) { cout << "could not load your image..."; return 0; } //原图,为了简单,自己手绘了一个色彩分明的图像 namedWindow("init_image", WINDOW_AUTOSIZE); imshow("init_image", src); //生成mask区域 inRange(src, Scalar(5, 30, 0), Scalar(100, 255, 100), mask); //inRange()无返回值,因为是3通道的,中间参数采用向量 namedWindow("mask_image", WINDOW_AUTOSIZE); imshow("mask_image", mask); //生成ROI区域 bitwise_and(src, src, dst, mask); //用混合方式,将mask以及原图混合,得出ROI不规则区域 namedWindow("output_image", WINDOW_AUTOSIZE); imshow("output_image", dst); //简而言之,就是2张图像的结合,得出结果。 waitKey(0); return 0;}
运行结果:
5)图像的混合操作:
3.5.1、图像的二进制运算操作:
说到二进制运算,我们总能想到&,|,!,^;
在opencv图像处理中,二进制操作又是哪些呢?
二进制函数 | 解析 |
---|---|
bitwise_and | void bitwise_and(InputArray src1, InputArray src2,OutputArray dst, InputArray mask=noArray()); 对图像每个像素值进行二进制“与”操作;简而言之,计算两个数组或一个数组和一个标量的逐元素逐位析取(或真或假,但不能既真又假)。 |
bitwise_or | void bitwise_or(InputArray src1, InputArray src2,OutputArray dst, InputArray mask = noArray()); 对图像每个像素值进行二进制“或”操作;简而言之,对两个元素计算按位“异或”运算数组或数组和标量。 |
bitwise_not | void bitwise_not(InputArray src, OutputArray dst,InputArray mask = noArray()); 对图像每个像素值进行二进制“取反”操作;简而言之,计算两个数组或数组与标量之间的每元素绝对差 |
bitwise_xor | void bitwise_xor(InputArray src1, InputArray src2,OutputArray dst, InputArray mask = noArray()); 对图像每个像素值进行二进制“异或”操作;简而言之,反转数组的每一位 |
bitwise_or简单操作:
程序代码:
#include <iostream>#include <opencv2/opencv.hpp>using namespace std;using namespace cv;int main() { Mat src, dst, add_src_dst; src = imread("C:\\Users\\ASUS\\Desktop\\1.jpg"); dst = imread("C:\\Users\\ASUS\\Desktop\\3.jpg"); if (src.empty() || dst.empty()) { cout << "could not load your image..."; return 0; } namedWindow("init_image1", WINDOW_AUTOSIZE); imshow("init_image1", src); namedWindow("init_image2", WINDOW_AUTOSIZE); imshow("init_image2", dst); //进行或操作 bitwise_or(src, dst, add_src_dst); //也可以采用与等,看自己需要 namedWindow("add_src_dst", WINDOW_AUTOSIZE); imshow("add_src_dst", add_src_dst); waitKey(0); return 0;}
运行结果:
3.5.2、图像的线性混合操作:
前提:两张图像的大小(size)、类型(type)必须一模一样。
a, 即alpha(alpha channels)的取值在[0,1]
程序代码:
#include <iostream>#include <opencv2/opencv.hpp>using namespace std;using namespace cv;int main() { Mat src, dst, add_src_dst; src = imread("C:\\Users\\ASUS\\Desktop\\1.jpg"); dst = imread("C:\\Users\\ASUS\\Desktop\\3.jpg"); if (src.empty() || dst.empty()) { cout << "could not load your image..."; return 0; } namedWindow("init_image1", WINDOW_AUTOSIZE); imshow("init_image1", src); namedWindow("init_image2", WINDOW_AUTOSIZE); imshow("init_image2", dst); if (src.type() == dst.type() && src.rows == dst.rows && src.cols == dst.cols) { double alpha = 0.45; addWeighted(src, alpha, dst, (1.0 - alpha), 0.0, add_src_dst); //这说明第一张图权重占比45%,第二张图权重占比55% //add(src, dst, add_src_dst, Mat()); //两个元素级的加运算 //multiply(src, dst, add_src_dst, 1.0); //两张图相乘 namedWindow("add_src_dst", WINDOW_AUTOSIZE); imshow("add_src_dst", add_src_dst); } else { cout << "could not blend image, the size of images is not same...\n"; return 0; } waitKey(0); return 0;}
运行结果:
四、其他图像操作函数:
1)waitKey()函数:
调用 waitKey() 会进入一个消息循环,来等待运行窗口上的按键动作命令。
2)cvtColor()函数:
将图像从一个颜色空间转换为另一个颜色空间,其中源图像存储在两个平面中。
3)Filp()函数:
选定轴翻转,0为x轴,即垂直翻转;1为y轴,即水平翻转;
写法:flip(src, dst, 0);
还有很多函数,等你来使用,这里不一一赘述了!
总结
本文讲述了图像的遍历,图像怎么选取ROI区域,图像的混合操作,以及其他小知识点!
如有错误,敬请指教!
发表评论
最新留言
关注你微信了!
[***.104.42.241]2025年03月23日 23时49分38秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
【△重点△】LeetCode - 4. 寻找两个正序数组的中位数——二分查找
2019-03-04
LeetCode - 5. 最长回文子串——字符串、动态规划
2019-03-04
全局锁和表锁 :给表加个字段怎么有这么多阻碍?
2019-03-04
二分查找与插入排序的结合使用
2019-03-04
892 三维形体的表面积(分析)
2019-03-04
16 最接近的三数之和(排序、双指针)
2019-03-04
279 完全平方数(bfs)
2019-03-04
875 爱吃香蕉的珂珂(二分查找)
2019-03-04
桌面图标的自动排列图标
2019-03-04
第十一届蓝桥杯python组第二场省赛-数字三角形
2019-03-04
Jquery使用需要下载的文件
2019-03-04
BST中某一层的所有节点(宽度优先搜索)
2019-03-04
广度优先搜索
2019-03-04
Dijkstra算法的总结
2019-03-04
SpringCloud和SprinBoot之间的关系
2019-03-04
C语言的运算符和表达式
2019-03-04
Vue实现选项卡功能
2019-03-04
uni-app请求头中携带token
2019-03-04
vue中接收后台的图片验证码并显示
2019-03-04