读写像素 读一个 GRAY 像素点的像素值(CV_8UC1) 1 2 3 4 Scalar intensity = img.at <uchar>(y, x); Scalar intensity = img.at <uchar>(Point (x, y));
读一个 BGR 像素点的像素值 1 2 3 4 5 6 7 8 9 10 Vec3b intensity = src.at <Vec3b>(x, y); int b = intensity [0 ];int g = intensity [1 ];int r = intensity [2 ];Vec3f intensity = img.at <Vec3f>(y, x); float blue = intensity.val [0 ]; float green = intensity.val [1 ]; float red = intensity.val [2 ];
Vec3b 与 Vec3F
Vec3b 对应三通道的顺序是 blue、green、red 的 uchar 类型数据。
Vec3f 对应三通道的 float 类型数据
把 CV_8UC1 转换到 CV32F1 实现如下:src.convertTo (dst, CV_32F);
修改像素值 灰度图像img.at (y, x) = 128;
RGB 三通道图像img.at (y,x)[0]=128; //blue
img.at (y,x)[1]=128; //green
img.at (y,x)[2]=128; //red
空白图像赋值img = Scalar (0);
ROI 选择Rect r (10, 10, 100, 100);
Mat smallImg = img (r);
获取灰度图像素点 接下来用灰度图的反色作为示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 #include <iostream> #include <opencv2\opencv.hpp> using namespace cv;using namespace std;int main (int argc, char **argv) { Mat src = imread ("C:\\Users\\Tim\\Desktop\\Image\\a.jpg" ); if (src.empty ()) { cout << "load image filed..." << endl; return -1 ; } namedWindow ("src_window" , CV_WINDOW_AUTOSIZE); imshow ("src_window" , src); Mat src_gray; cvtColor (src, src_gray, CV_BGR2GRAY); namedWindow ("src_gray_window" , CV_WINDOW_AUTOSIZE); imshow ("src_gray_window" , src_gray); int height = src_gray.rows; int width = src_gray.cols; for (int row = 0 ; row < height;row++){ for (int col = 0 ; col < width; col++) { int gray = src_gray.at <uchar>(row, col); src_gray.at <uchar>(row, col) = 255 - gray; } } namedWindow ("gray_window" ,CV_WINDOW_AUTOSIZE); imshow ("gray_window" , src_gray); waitKey (0 ); return 0 ; }
获取三通道图像素点 对于三通道的像素点获取,以获取原图的反色图为例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 #include <iostream> #include <opencv2\opencv.hpp> using namespace cv;using namespace std;int main (int argc, char **argv) { Mat src = imread ("C:\\Users\\Tim\\Desktop\\Image\\a.jpg" ); if (src.empty ()) { cout << "load image filed..." << endl; return -1 ; } namedWindow ("src_window" , CV_WINDOW_AUTOSIZE); imshow ("src_window" , src); Mat src_gray; cvtColor (src, src_gray, CV_BGR2GRAY); int height = src_gray.rows; int width = src_gray.cols; Mat dst; dst.create (src.size (), src.type ()); height = src.rows; width = src.cols; int cn = src.channels (); for (int row = 0 ; row < height; row++) { for (int col = 0 ; col < width; col++) { if (cn == 1 ) { int gray = src_gray.at <uchar>(row, col); src_gray.at <uchar>(row, col) = 255 - gray; } else if (cn == 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; } } } namedWindow ("gray_window" ,CV_WINDOW_AUTOSIZE); imshow ("gray_window" , dst); waitKey (0 ); return 0 ; }
上面的反色,使用 API 也可以做到:bitwise_not (src, dst)
三通道图转为灰度图的其他方式
通过把原图中的像素点设定为像素点中的最大或者最小值也是可以达到转换为灰度图的效果!
图像混合 理论 - 线性混合操作
相关 API (addWeighted) 参数 1:输入图像 Mat – src1 参数 2:输入图像 src1 的 alpha 值 参数 3:输入图像 Mat – src2 参数 4:输入图像 src2 的 alpha 值 参数 5:gamma 值 参数 6:输出混合图像 注意点:两张图像的大小和类型必须一致才可以
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 #include <iostream> #include <opencv2\opencv.hpp> using namespace cv;using namespace std;int main (int argc, char **argv) { Mat src1 = imread ("C:\\Users\\Tim\\Desktop\\Image\\a.jpg" ); Mat src2 = imread ("C:\\Users\\Tim\\Desktop\\Image\\b.jpg" ); Mat ret; if (src1.empty () || src2.empty ()) { cout << "load image filed..." << endl; return -1 ; } namedWindow ("src1" , CV_WINDOW_AUTOSIZE); imshow ("src1" , src1); namedWindow ("src2" , CV_WINDOW_AUTOSIZE); imshow ("src2" , src2); double alpha = 0.5 ; if (src1.rows == src2.rows && src1.cols == src2.cols { addWeighted (src1, alpha, src2, (1.0 - alpha), 0 , ret); namedWindow ("ret" , CV_WINDOW_AUTOSIZE); imshow ("ret" , ret); } else { cout << "Images vary in size or type!" << endl; return -1 ; } waitKey (0 ); return 0 ; }
这是两张图片各占 50% 的权重合成的图像:
对比度和亮度调整 图像亮度本质上图像中每个像素的亮度,每个像素的亮度本质上 RGB 值的大小,RGB 值为 0,则像素点为黑色,RGB 都为 255 时像素点最亮,为白色。对比度则是不同像素点之间的差值,差值越大,对比度越明显。 图像变换可以看作如下:
调整图像亮度和对比度属于像素变换 - 点操作,搞清楚原理下面开始撸代码:
代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 #include <iostream> #include <opencv2\opencv.hpp> using namespace cv;using namespace std;int main (int argc, char **argv) { Mat src = imread ("C:\\Users\\Tim\\Desktop\\Image\\a.jpg" ); Mat dst; if (src.empty ()) { cout << "load image filed..." << endl; return -1 ; } char *input_win = "input_win" ; namedWindow (input_win, CV_WINDOW_AUTOSIZE); imshow ("input_win" , src); int height = src.rows; int wight = src.cols; dst = Mat::zeros (src.size (), src.type ()); float alpha = 0.4f ; float beta = 0.0f ; for (int row = 0 ; row < height; row++) { for (int col = 0 ; col < wight; col++) { if (src.channels () == 3 ){ float b = src.at <Vec3b>(row, col)[0 ]; float g = src.at <Vec3b>(row, col)[1 ]; float r = src.at <Vec3b>(row, col)[2 ]; dst.at <Vec3b>(row, col)[0 ] = saturate_cast <uchar>(b*alpha + beta); dst.at <Vec3b>(row, col)[1 ] = saturate_cast <uchar>(g*alpha + beta); dst.at <Vec3b>(row, col)[2 ] = saturate_cast <uchar>(r*alpha + beta); } else if (src.channels () == 1 ) { float v = src.at <uchar>(row, col); dst.at <uchar>(row, col) = saturate_cast <uchar>(v*alpha + beta); } } } char *output_win = "output_win" ; namedWindow (output_win, CV_WINDOW_AUTOSIZE); imshow (output_win, dst); waitKey (0 ); return 0 ; }
从代码中可以看出:如果将值乘上差异倍数,那么 像素点之间的差异倍数(alpha)越大,像素点之间的差异也就越大,这样导致的直接结果就是图像的对比度增强 , 增益变量越大,那么像素本身的值在增大,导致的结果就是亮度增强
演示效果
重要的 API
Mat new_image = Mat::zeros (image.size (), image.type ());
创建一张跟原图像大小和类型一致的空白图像、像素值初始化为 0
saturate_cast (value)
确保值大小范围为 0~255 之间
Mat.at (y,x)[index]=value
给每个像素点每个通道赋值