梳理程序笔记(二)

1,dmLocation()中的blockThreshold()

原始的图片为480x640的图片,进过opencvresize函数将图片缩小成240x640,因为光源照射而截取的图片,实际上并不是每一区域的光照强度都是相同的,即光照不均匀。因此,如果直接使用opencv中的threshold()将图片二值化,会含有较大的误差。所以,采取将图片分成一个个的小方格,分别求每个小方格的threshold()对每个小方格进行二值化

1.1 使用opencv的Rect类将图片切成width*height的大小,通过(x,y)确定开始切的位置。
Mat srcCut, srcImag  //srcCut存放切片后的方格图;srcImag输入的图片
Rect rect;			//创建一个矩形实例
rect.width = 80;	//设置成80*80的的小方格
rect.height = 80;
rect.x = 0;			//从(x,y)坐标点处开始切
rect.y = 0;
srcCut = srcImag(rect);	//srcCut成为了srcImag的0*0区域大小为80*80的引用数据
float meanV = mean(srcSec)[0] * _thresh;  
threshold(srcSec, srcSec,meanV, 255, THRESH_BINARY_INV)  //对srcCut这个区域二值化

threshold()

double threshold( InputArray src, 
                 OutputArray dst,
                 double thresh, 
                 double maxval, 
                 int type );

其中,src为输入的图像矩阵;dst为输出的图像矩阵;thresh为阈值,图像矩阵的光照均值;maxval为输出的图像矩阵dst中的最大值;

Type参数类型如下:

参数类型含义
THRESH_BINARYsrc中像素点如果大于thresh,则对应像素点位置的dst像素点就设为maxvel;否则为0
THRESH_BINARY_INV这个效果和THRESH_BINARY的效果翻过来
THRESH_TRUNCsrc中像素点如果大于thresh,则对应像素点位置的dst像素点就设为maxvel;否则为src中的原始值
THRESH_TOZEROsrc中像素点如果大于thresh,则对应像素点位置的dst像素点就设为src的值;否则为0
THRESH_TOZERO_INV和THRESH_TOZERO的效果相反
THRESH_MASK不支持
THRESH_OTSU不支持32位
THRESH_TRIANGLE不支持32位

具体可以描述成如下公式

参数:THRESH_BINARY−−−−dst(x,y)={maxval,src(x,y)>thresh0,otherwise 参数:THRESH\_BINARY ---- dst(x,y)=\begin{cases} maxval, & src(x,y)>thresh\\ 0, & otherwise\\ \end{cases} THRESH_BINARYdst(x,y)={maxval,0,src(x,y)>threshotherwise


参数:THRESH_BINARY_INV−−−−dst(x,y)={0,src(x,y)>threshmaxval,otherwise 参数:THRESH\_BINARY\_INV ---- dst(x,y)=\begin{cases} 0, & src(x,y)>thresh\\ maxval, & otherwise\\ \end{cases} THRESH_BINARY_INVdst(x,y)={0,maxval,src(x,y)>threshotherwise


参数:THRESH_TRUNC−−−−dst(x,y)={threshhold,src(x,y)>threshsrc(x,y),otherwise 参数:THRESH\_TRUNC ---- dst(x,y)=\begin{cases} threshhold, & src(x,y)>thresh\\ src(x,y), & otherwise \\ \end{cases} THRESH_TRUNCdst(x,y)={threshhold,src(x,y),src(x,y)>threshotherwise


参数:THRESH_TOZERO−−−−dst(x,y)={src(x,y),src(x,y)>thresh0,otherwise 参数:THRESH\_TOZERO ---- dst(x,y)=\begin{cases} src(x,y), & src(x,y)>thresh\\ 0, & otherwise \end{cases} THRESH_TOZEROdst(x,y)={src(x,y),0,src(x,y)>threshotherwise


参数:THRESH_TOZERO−−−−dst(x,y)={0,src(x,y)>threshsrc(x,y),otherwise 参数:THRESH\_TOZERO ---- dst(x,y)=\begin{cases} 0, & src(x,y)>thresh\\ src(x,y), & otherwise \end{cases} THRESH_TOZEROdst(x,y)={0,src(x,y),src(x,y)>threshotherwise

1.2 使用opencv的mean()

opencv中计算单通道所有元素均值和标准差分别使用mean()和meanStdDev(),其中mean()的返回值是array矩阵,通过数组的形式访问,第0个元素就是均值大小;meanStdDev()的返回值是Mat类型的数据。

blockThreshold中

float meanV = mean(srcSec)[0] * _thresh;

均值为什么要乘 “_thresh” ????
这是测试的经验值,一般在0.7-0.8之间,而不是简单的1

2 opencv中的findContours()

findContours()函数是寻找图片中物体的轮廓信息。

void findContours( InputOutputArray image, 
                  OutputArrayOfArrays contours,
                  OutputArray hierarchy, 
                  int mode,
                  int method, 
                  Point offset=Point());

其中,image:输入图像,图像必须为8-bit单(CV_8UC1)通道图像,图像中的非零像素将被视为1,0像素保留其像素值,故加载图像后会自动转换为二值图像。如果第四个参数为cv::RETR_CCOMP或cv::RETR_FLOODFILL,输入图像可以是32-bit整型图像(CV_32SC1)
contours: 检测到的轮廓,每个轮廓都是以点向量的形式进行存储即使用point类型的vector表示
hierarchy: 可选的输出向量(std::vector),包含了图像的拓扑信息,作为轮廓数量的表示hierarchy包含了很多元素,每个轮廓contours[i]对应hierarchy中hierarchy[i][0]~hierarchy[i][3],分别表示后一个轮廓,前一个轮廓,父轮廓,内嵌轮廓的索引,如果没有对应项,则相应的hierarchy[i]设置为负数。

mode轮廓检索模式,可以通过cv::RetrievalModes()查看详细信息,如下 :

参数含义
RETR_EXTERNAL表示只检测最外层轮廓,对所有轮廓设置hierarchy [1]][2]=hierarchy[i][3]=-1
RETR_LIST提取所有轮廓,并放置在list中,检测的轮廓不建立等级关系
RETR_CCOMP提取所有轮廓,并将轮廓组织成双层结构(two-level hierarchy),顶层为连通域的外围边界,次层位内层边界
RETR_TREE提取所有轮廓并重新建立网状轮廓结构

**method:**轮廓近似方法可以通过cv::ContourApproximationModes()查看详细信息,如下所示:

参数含义
CHAIN_APPROX_NONE获取每个轮廓的每个像素,相邻的两个点的像素位置差不超过1
CHAIN_APPROX_SIMPLE压缩水平方向,垂直方向,对角线方向的元素,值保留该方向的重点坐标,如果一个矩形轮廓只需4个点来保存轮廓信息
CHAIN_APPROX_TC89_L1和CHAIN_APPROX_TC89_KCOS使用Teh-Chinl链逼近算法中的一种

**offset:**轮廓点可选偏移量,有默认值Point(),对ROI图像中找出的轮廓。

轮廓提取完成后,可以通过drawContours()画出轮廓图

void drawContours(
	InputOutputArray image, // 输入图像
	InputArrayOfArrays contours, // 轮廓点集
	int contourIdx, // 需要绘制的轮廓的指数 (-1 表示 "all")
	const cv::Scalar& color, // 轮廓的颜色
	int thickness = 1, // 轮廓线的宽度
	int lineType = 8, //  轮廓线的邻域模式('4'邻域 或 '8'邻域)
	InputArray hierarchy = noArray(), // 可选 (从 findContours得到)
	int maxLevel = INT_MAX, // 轮廓中的最大下降
	Point offset = Point() // (可选) 所有点的偏移
)
3 opencv中的RotatedRect类

RotatedRect有三个属性:

  1. 矩形的中心点;

  2. 矩形的尺寸;

  3. 角度。

这个和rect就对了一个角度,因为需要rotate,

vector<RotatedRect> rotRects;  //存放最小外接矩形
4 opencv-------ROI

ROI------region of interest,感兴趣的区域。对于图像的处理,并不是对所有的部分都感兴趣,因此对于感兴趣的部分的提和处理,就称其为ROI。

5 代码分析
  1. dmLocation()中中的轮廓尺寸,面积约束,比例约束都是为了保证提取的矩形轮廓是我们自己的二维码的轮廓,而不是其他东西的轮廓,即保证找到的是二维码。

  2. 对于rect的排序,以最小外接矩形的的中心点到图片中心点的位置距离排序,是为了获得最逼近摄像头正下方附近区域的轮廓信息。
    6 代码举例
    举个栗子:

void do_it()
{
    string filePath = "D:/qt_work/Project_QR_ribbon_position/dmc/test00/pictures/singalCode.jpg";
    float meanV;
    Mat image = imread(filePath);
    Mat grayImag, rectImag;
    std::cout<<image.size()<<std::endl;
    //resize picture
    resize(image, image, Size(320, 240), 0, 0, INTER_NEAREST);
    imshow("origin picture", image);
    //convert image from BGR to GRAY
    cvtColor(image, grayImag, CV_BGR2GRAY);
    meanV = mean(image)[0];
    //threshold image
    threshold(grayImag, rectImag, meanV, 255, THRESH_BINARY_INV);
    imshow("threshold", rectImag);
    //find contour rectangle
    vector<vector<Point2i>> contours;
    vector<Vec4i> hierarchy;
    findContours(rectImag, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE, Point(0, 0));
    drawContours(rectImag, contours, -1, Scalar::all(255));
    imshow("contours", rectImag);
    waitKey(0);
}
int main()
{
    do_it();
    return 0;
}

执行结果:
原始图片:
原始图片
二极化后的图片:
在这里插入图片描述
全部轮廓提取:
在这里插入图片描述
外部轮廓提取:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值