1.cv::Mat有若干成员函数可以获取图像属性,at(int y,int x)可以用来存取图像元素,但是必须知道图像数据类型!
例:
image.at<cv::Veb3b>(j,i)[channel]=value;//彩色图像,其中channel注明了颜色通道号;```
类似的,open cv 还有二元,四元向量;
```cv::Mat_<uchar>im2=image;
im2(50,100)=0;//存取第50行,100列//重载了运算符()```
##2.使用指针遍历图像(使用双重循环遍历所有的像素值)
颜色缩减函数:
void colorReduce(cv::Mat&image,int div=64)
{
int n1=image.rows;//行数
int nc=image.cols*image.channels();//每行的元素个数
for(int j=0;j<n1;j++)//得到第j行的首地址
{
uchar* data=image.ptr<uchar>(j);//ptr可以得到任意行的首地址,此处返回第j行的首地址
for(int i=0;i<nc;i++)
{
//处理每一个像素
data[i]=data[i]/div*div+div/2
}//像素处理完成
}//行处理完成
}```
主函数:
image=cv::imread("boldt.jpg");
//处理图像(调用函数)
colorReduce(image);
//显示图像
cv::namedWindow("image");
cv::imshow("image",image);```
#3.使用迭代器遍历彩色图像
void colorReduce(cv::Mat &image,int div=64)
{
cv::Mat_<cv::Vec3b>::iterator it=image.begin<cv::Vec3b>();//得到起始位置的迭代器
cv::Mat_<cv::Veb3b>::iterator itend=image.end<cv::Veb3b>();//得到终止位置的迭代器
for(;it!=itend;++it)
{//处理每个像素
(*)it[0]=(*)it[0]/div*div+div/2;
(*)it[1]=(*)it[1]/div*div+div/2;
(*)it[2]=(*)it[2]/div*div+div/2;
}
} ```
4.使用卷积核进行滤波,编写图像锐化函数
void sharpen2D(const cv::Mat &image,cv::Mat &result)
{
cv::Mat kernel(3,3,CV_32f,cv::Scalar(0));//构造核,所有的项初始化为0
//对核元素赋值
kernel.at<float>(1,1)=5.0;
kernel.at<float>(1,0)=-1.0;
kernel.at<float>(1,2)=-1.0;
kernel.at<float>(0,1)=-1.0;
kernel.at<float>(2,1)=-1.0;
//对图像进行滤波
cv::filter2D(image,result,image.depth(),kernel);
}```
#5.进行简单的图像运算(此处仅针对两个输入图像具有相同尺寸)
(1)加、减、乘、除
cv::add(image1,w1,image2,w2,b,result) ——> open cv2 里面对运算符进行了重载,可以直接写符号: result=0.7image1+0.9image2
cv::substract 、cv::absdiff、cv::multiply、cv::divide```
(2)位运算符
cv::bitwise_and、cv::bitwise_or 、cv::bitwise_xor 、cv::bitwise_not
(3)找矩阵最大最小值、矩阵的一些运算
cv::max、 cv::min、矩阵求逆m1.inv()、矩阵转置m1.t()、矩阵的行列式m1.determinate()、向量模v1.norm()、向量叉乘v1.cross(v2)、向量点乘v1.cross(v2)
(4)只接受一个输入的操作符
cv::sqrt、 cv::pow 、cv::abs 、cv::cuberoot 、cv::exp 、cv::log
6.对图像的一个通道进行操作后,再合并
//创建一个图像向量
std::vector<cv::Mat>planes;
//将一个三通道图像分离成三个单通道图像
cv::spirit(image,planes);```
//将新图层叠加到蓝色通道
planes[0]+=image2;
//将三个单通道图像合并为一个三通道图像
cv::merge(planes,result);```
7.定义感兴趣区域ROI(此处针对两张图像具有不同大小尺寸,比如想在原图像上加一个logo)
只要ROI大小和logo图片大小一致,则可以调用cv::add;ROI位置决定了logo图像被插入的位置;
//定义图像ROI
cv::Mat imageROI;//ROI与他的父图像指向同一块内存缓冲区
imageROI=image(cv::Rect(385,270,logo.cols,logo.rows))或者imageROI=image(cv::Range(270,270+logo.rows),cv::Range(385,385+logo.cols))
//插入logo 或 //加载掩模(必须是灰度图)
cv::addWeighted(imageROI,1.0,logo,0.3,0.,imageROI) cv::Mat mask=cv::imread("logo.bmp",0) //此处0代表灰度图像
//通过掩模拷贝ROI
logo.copyTo(imageROI,mask)```
8.类的设计
class ColorDetector{
private:
int minDist; //最小可接受距离
cv::Vec3b target;//目标色
cv::Mat result;//结果图像
//构造函数
ColorDetector():minDist(100){
target[0]=target[1]=target[2]=0; //初始化默认参数
}
//设置颜色距离阈值,阈值必须是正,否则设为0
void setColorDistanceThreshold(int distance){
if(distance<0) distance=0;
minDist=distance;
}
//获取颜色距离阈值
int getColorDistanceThreshold() const{
return minDist;
}
//设置需检测的颜色
void setTargetColor(unsigned char blue,unsigned char green,unsigned char red){
target[0]=blue; arget[1]=green; target[2]=red;
}
//获取需检测的颜色
cv::Vec3b getTargetColor() const{
return target;
}
cv::Mat ColorDetctor::process(const cv::Mat &image){
result.create(image.rows,image.cols,CV_8U);//按需重新分配二值图像,与输入图像的尺寸相同,但只有一个通道
//得到迭代器
cv::Mat_<cv::Vec3b>::const_iterator it=image.begin<cv::Vec3b>();
cv::Mat_<cv::Vec3b>::const_iterator itend=image.end<cv::Vec3b>();
cv::Mat_<unchar>::iterator itout=result.begin<unchar>();
//遍历每个像素
for(;it!=itend;++it,++itout){
if(getDistance(*it)<minDist) *itout=255;
else *itout=0;
}
return result;
}
//计算与目标颜色的距离
int getDistance(const cv::Vec3b& color)const{
return abs(color[0]-target[0])+abs(color[1]-target[1])+abs(color[2]-target[2]);
}
}
int main(){
//1.创建图像处理对象
ColorDetector cdetect;
//2.读取输入图像
cv::Mat image=cv::imread("1.jpg");
if(!image.data)
return 0;
//3.设置输入参数
cdetect.setTargetColor(130,190,230);//蓝天的颜色
cv::namedwindow("result");
//4.处理并显示结果
cv::imshow("result",cdetect.process(image))
cv::waitkey();
return 0;
}```
9.控制器实现类之间的通信