【opencv】(四)Operations with images
作者:互联网
目录
说在前面
- opencv版本:4.0.1
- 操作系统:win10
- vs版本:2017
- 官方文档:Operations with images
- 其他说明:自学,记录,demo
Input&Output
-
imread
读取图像,默认3通道(即BGR)Mat img = imread(filename);
读取图像为灰度图
Mat img = imread(filename, IMREAD_GRAYSCALE);
查找资料貌似不能用这个读取gif
-
imwrite
imwrite(filename, img);
jpg格式保存为png格式
Basic operations with images(图像基操)
-
Accessing pixel intensity values(访问像素值)
要获取像素平均强度值,我们需要知道图像的通道数以及图像的类型。
首先我们考虑灰度图,其访问方式为:
Scalar intensity = img.at<uchar>(y, x); //对于at<>中的取值 //If matrix is of type CV_8U then use Mat.at<uchar>(y,x). 无符号char型 //If matrix is of type CV_8S then use Mat.at<schar>(y,x). 有符号char型 //If matrix is of type CV_16U then use Mat.at<ushort>(y,x). 无符号short型 //If matrix is of type CV_16S then use Mat.at<short>(y,x). 有符号short型 //If matrix is of type CV_32S then use Mat.at<int>(y,x). //If matrix is of type CV_32F then use Mat.at<float>(y,x). //If matrix is of type CV_64F then use Mat.at<double>(y,x). //若对(y,x)这种访问方式不习惯,opencv还提供了另一种方式 //Scalar intensity = img.at<uchar>(Point(x, y)); /*对于Scalar typedef struct Scalar { double val[4]; }Scalar; */
对于为何使用(y,x)可以参考下图,坐标系如下左图,img.at (y, x)的函数原型为Mat::at(row, col)
然后我们考虑多通道的图像Vec3b intensity = img.at<Vec3b>(y, x); uchar blue = intensity.val[0]; uchar green = intensity.val[1]; uchar red = intensity.val[2]; //对于Vec3b // typedef Vec<uchar, 3> cv::Vec3b //其他还有Vec3f,规则类似 // typedef Vec<float, 3> cv::Vec3f
同样,我们可以通过这种方式更改其对应的值
//单通道,这里也可以访问三通道的图像,但是访问的不是(y,x)那个像素 img.at<uchar>(y, x) = 128; //三通道,CV_8UC3 img.at<Vec3b>(y,x)[0] = 128; img.at<Vec3b>(y,x)[1] = 128; img.at<Vec3b>(y,x)[2] = 128;
最后,opencv提供points array到matric的转换
std::vector<Point2f> points; points.push_back(Point2f(0, 1)); points.push_back(Point2f(1, 1)); points.push_back(Point2f(2, 1)); points.push_back(Point2f(5, 1)); Mat pointsMat = Mat(points);
输出结果为:
-
Memory management and reference counting(内存管理&引用计数)
由于Mat类维护的是图像/矩阵的信息以及一个指向数据的指针,可能会出现多个Mat的指针指向同一块数据,这样我们就需要考虑这块数据的释放问题(何时释放、被谁释放等)
-
Primitive operations
opencv提供了一系列基本的图像处理操作,这里举个栗子。
Mat img, grey; //原图 img = imread("test1.jpg"); imshow("operations_before", img); //定义一个矩形(x,y,宽,高)原图的右半部分 Rect r(img.cols / 2, 0, img.cols / 2, img.rows); //设置感兴趣区域,用的下面这种方法 //可以知道smallImg中的数据指针指向的是img对应的数据部分 //没有发生内存拷贝 Mat smallImg = img(r); //这里同理,原图的左半部分 Rect rC(0, 0, img.cols / 2, img.rows); Mat smallImgC = img(rC); //我们在这里克隆一份左半部分 Mat src = smallImgC.clone(); //将灰度图保存一下,src、grey指向不同的数据 cvtColor(src, grey, COLOR_BGR2GRAY); //然后将src复制到smallImg,也就是原图的右半部分 src.copyTo(smallImg, grey); imshow("operations",img);
-
Visualizing images(显示图像)
- 使用namedWindow(“image”, WINDOW_AUTOSIZE)来创建窗口;
- WINDOW_AUTOSIZE,窗口大小适合Mat大小,且不可更改
- WINDOW_FREERATIO,在生成窗口后可以更改窗口大小(就像你调整浏览器窗口大小那样)
- 注意,这里的Sobel等函数我们暂时先不管
Mat img = imread("image.jpg"); Mat grey; cvtColor(img, grey, COLOR_BGR2GRAY); Mat sobelx; Sobel(grey, sobelx, CV_32F, 1, 0); double minVal, maxVal; minMaxLoc(sobelx, &minVal, &maxVal); //find minimum and maximum intensities Mat draw; sobelx.convertTo(draw, CV_8U, 255.0/(maxVal - minVal), -minVal * 255.0/(maxVal - minVal)); namedWindow("image", WINDOW_AUTOSIZE); imshow("image", draw); waitKey();
-
补充(imread PNG格式图片)
- 我们知道png格式的图片有的地方是透明的,即没有像素,那么读取到Mat中是什么亚子的呢?
- 我们使用一张png图片进行实验
Mat img = imread("pikachu.png"); Vec3b intensity = img.at<Vec3b>(0, 0); cout << intensity << endl; imshow("png", img);
- 结果如下图,可以看到无像素的位置的intensity为[0,0,0]
- 然后测试其转换成灰度图后无像素的位置的值也是0;
- 这样我们就知道copyTo()函数中mask的作用了,通过判断mask像素值是否为0来决定是否要将该位置的src像素复制到目标图像上,这样我们就可以只关注png图像中有像素的地方了。
src.copyTo(smallImg, grey); /* void cv::Mat::copyTo ( OutputArray m, InputArray mask )const*/
- 就像这样
- 最后还有一个问题要考虑,像素值为0其实还可以是纯黑色,如果图像原本就有一块纯黑的部分,那么是会当成无像素处理还是黑色来处理呢?(自己先思考下)
END-2019.6.27~2019.6.28
标签:Operations,Mat,img,像素,opencv,intensity,图像,images,CV 来源: https://blog.csdn.net/qq_33446100/article/details/93908007