OpenCV关于图像处理的预备知识
一. 操作像素
0. 基本概念
- Scalar表示像素点的值(实际上是个结构体),Scalar(0)表示将该像素点的像素值设为0(单通道)
- 图像由矩阵表示(数组存储,一维,二维,三维)
- 矩阵有维度 —dims
- 每个维度上的每个点表示像素点 — elemSize() 表示每个像素点占的字节数,total()获得总的像素点个数
- 像素点有通道(单通道或多通道,多通道最多为4) — channels() 表示每个像素点所占的通道总数(灰度图就是单通道,彩色图就是三通道的)
- 每个通道又由相应的位数来表示该通道上颜色的深浅 — CV_16SC1表示单通道,每个通道用16位(2个字节)表示,S表示有符号整数,C后面数字表示通道数;CV_64FC3表示三通道,每个通道用64位(8字节)浮点数表示)
- data:存放矩阵数据内存中的首地址
- step: 是一个数组,表示总字节数,step[0]表示第二个维度上包含的字节数,,step[1]表示第三维度上包含的字节数,以此类推…
- step1:是函数,step(0)表示总通道数,step1(0)表示第二维度上的总的通道数,step1(1)表示第三维度上总的通道数
- elemSize:每个像素点的总的字节数
- elemSize1:每个通道的字节数
- depth:每个像素的位数,取值为0到6
enum { CV8U=0, CV8S=1, CV16U=2, CV16S=3, CV32S=4, CV32F=5, CV_64F=6 }
- 取像素点的各个通道值
单通道: img.at<uchar>(i,j) 三通道: img.at<Vec3b>(j,i)[0] img.at<Vec3b>(j,i)[1] img.at<Vec3b>(j,i)[2]
- 图像按颜色分类:
二值图:图像颜色只有黑白两种构成 无符号位的单通道 灰度图:图像颜色由白到黑色之间颜色构成 无符号位的单通道 彩色图:图像颜色由bgr三原色构成的各种颜色构成 三通道(四通道带有透明度)
1. 载入,显示,保存图像
- imread(“图像名”,int flag);
flag: \>0:返回3通道的彩色图 特例:如果原图为黑白图,flag=2时,返回的还是黑白图非彩色图 =0:返回灰度图 <0:返回原图(带alpha通道)
- imwrite(“文件名”,要保存图像的Mat对象);
- imshow(“图像名”,Mat对象);
2. 使用迭代器遍历图像
Mat_<Vec3b>::interator it = image.begin<Vec3b>();
Mat_<Vec3b>:interator itenfd = image.end<Vec3b>();
for(;it!=itend;++it){
(*it)[0] = (*it)[0]/div*div+div/2;
(*it)[1] = (*it)[1]/div*div+dov/2;
(*it)[2] = (it)[2]/div*div+div/23;
}
3.遍历图像和邻域操作
应用实例: 图像的锐化
锐化公式: sharpened_pixel = 5*current-left-right-up-down; //该位置的像素值的5倍减去与其相邻的点的像素值,必须是上下左右都有像素
核矩阵:
图像滤波器:
4. 颜色缩减
- 例如:CV_8UC3 — 三通道的八位无符号整数表示像素值,像素值一共有256256256种可能
倘若一幅图包含这些像素值,存储起来是很浪费空间的
因此需要缩减颜色种类的数量,也就是像素值的所有可能取值的情况和
- 具体的颜色缩减的策略:
5. 图像掩模(或掩模)
- 为8位单通道图像(灰度图或二值图)
- 掩码某个位置为0,则在此位置上操作不起作用, 掩码某个位置不为0,则在此位置上操作起作用
- 可以用来提取不规则ROI
- 示例代码
#include "opencv2/opencv.hpp" using namespace cv; /* 掩码的使用 掩码: 8位单通道图像 从一幅图中选取感兴趣区域,使用掩码(形状是根据掩码的非零像素形状决定的) 可以先创建一个像素值全为零的 Mat对象,然后在图像中画长方形,圆形,多边形等 (设置该区域的像素值为255) 作为掩码(即要操作的区域) 如果 按照掩码操作后 得到图像的边缘有问题 ,肯定是边缘部分的黑色不够完善,则此时需要二值化操作,将边缘部分一律变黑 把多通道的图像怎么读成单通道的图像的原理 */ void main() { Mat img = imread("a.png");//背景 Mat girlImg = imread("girl.jpg");//前景女孩 Mat mask = imread("mask.jpg",0);//掩码 Mat mask1 = Mat::zeros(girlImg.size(), CV_8UC1); Mat logo = imread("opencv.jpg"); Mat mask2 = imread("opencv.jpg", 0); //图像逻辑相加 中 使用 掩码 ,像素值为0的区域不用考虑 Mat img1 = imread("3.jpg"); Mat img2 = imread("4.jpg"); Mat mask3 = Mat::ones(img1.size(), CV_8UC1); circle(mask3, Point(mask3.cols / 2, mask3.rows / 2), 100, Scalar(0), -1, 8); Mat dst1 = img2.clone(); add(img1, img2, dst1,mask3); namedWindow("dst1", CV_WINDOW_NORMAL); imshow("dst1", dst1); circle(mask1, Point(mask.rows / 2, mask.cols / 2), 100,Scalar(255), -1, 8); //imwrite("mask1,jpg", mask1); //对mask2像素值取反,255变为0,变成黑色的掩码区域即不用考虑了 bitwise_not(mask2, mask2); namedWindow("mask2",CV_WINDOW_NORMAL); imshow("mask2", mask2); //二值化取反后的mask2, 为了边缘处理 threshold(mask2, mask2, 100, 255, THRESH_BINARY); namedWindow("二值化后的mask2",CV_WINDOW_NORMAL); imshow("二值化后的mask2",mask2); //在背景图片中选取 两块感兴趣区域 Mat imgROI = img(Rect(106, 128, girlImg.cols, girlImg.rows)); Mat imgROI1 = img(Rect(0, 0, logo.cols, logo.rows)); //把两张前景图片按照掩码的方式 复制到 感兴趣区域中 girlImg.copyTo(imgROI,mask1); logo.copyTo(imgROI1,mask2);//复制非黑色区域的部分 imshow("dsr", img); imwrite("result.png", img); waitKey(0); }
- 运行结果
6. ROI(感兴趣区域) — regin of interest
- 可以只对感兴趣区域进行图像的处理,例如图像的覆盖,区域图像颜色改变
- 在某一幅图中选出感兴趣区域
Mat img; Mat imgROI; imgOROI = img(Rec(左上角横坐标,左上角纵坐标,宽度,高度); 或者 imgROI = img(Range(起始行数,终止行数).Range(起始列数,终止列数)); imgROI = img.rowRange(start,end);//创建包含原始图像的特定行 imgROI = img.colRange(start,end);//创建包含原始图像的特定列 row(i) 是 rowRange(start,end)的特例,返回的是Mat对象 col(j) 是 colRange(start,end)的特例,返回的是Mat对象
- 在原图中选出感兴趣区域,并用logo这张图进行添加
1.像素值相加处理 Mat imgROI;//声明感兴趣区域 Mat img;//原图像 imgROI = img(Rec(0,0,logo.cols,logo.rows));//在原图像抠出感兴趣区域(矩形) addWeighted(imgROI,1.0,logo,0.3,0.,imgROI);//在感兴趣区域与logo图像直接相加(可能出现像素饱和) 2.像素值的替换 imgROI = img(Rec(23,34,logo.cols,logo.rows));//声明感兴趣区域 Mat mask = immread("logo.bmp",0);//加载掩模.必须是灰度图 logo.copyTo(imgROI,mask);//通过掩模拷贝ROI
7. 图像的运算
- 算术运算
- +
dst = img1 + img2;
- add()
add(img1,img2,dst);
- addWeighted()
addWeighted(img1,0.5,img2,0.5,0,dst);//0.5是各自图像像素值的比重
- –
dst = img1 -img2;
- substract()
substract(img1, img1,dst); 像素差小于零按零计算
- absdiff()
absdiff(img1,img2,dst); 像素差按绝对值计算
- *
dst = A * img1;
- /
dst = img1 /A;
- +
- 逻辑运算
- bitwise_and(srcImg1,srcImg2,outImg,mask);
- bitwise_or(srcImg1,srcImg2,outImg,mask);
- bitwise_not(srcImg,outImg,mask);
- bitwise_xor(srcImg1,srcImg2,outImg,mask);//异或运算,各自图像中独有的部分的并集