////第二个部分,获得条码区域////
Mat sobel;
Mat canny;
Mat canny_output;
int imax = 0;
int imaxcontour = -1;
std::vector<std::vector<cv::Point>>contours;
Mat cannyClone= Mat::zeros(Size(gray.cols,gray.rows),gray.type());
Canny(gray,canny,100,255);
Mat element = getStructuringElement(MORPH_ELLIPSE,Size(7,3));
morphologyEx(canny,canny,CV_MOP_DILATE,element);
morphologyEx(canny,canny,CV_MOP_ERODE ,element);
findContours(canny,contours,CV_RETR_TREE,CV_CHAIN_APPROX_NONE);
for (int i=0;i<contours.size();i++)
{
int itmp = contourArea(contours);
if (imaxcontour < itmp )
{
imax = i;
imaxcontour = itmp;
}
}
//找到轮廓的处理
Rect boundRect;//最小外接矩形
drawContours(cannyClone,contours,imax,Scalar(255),-1);
boundRect = boundingRect(Mat(contours[imax]));
Mat srcRoi = src(boundRect);
imwrite("barcode.jpg",srcRoi);
三、难点攻关:
3.1第5和第9压板的特殊情况。
由于第5和第9压板的颜色和背景颜色非常接近,所以采用特殊的方法来进行处理。通过观察,结合常理。压板打开之后,必然带来的结果就
是下垂并且将下面的字符牌遮挡。那么可以通过反过来判断字符牌是否被遮盖来判断压板是否被打了下来。
(字符遮挡)
//将第5和第9条单独取出来
Mat roi05 = src(Rect(6*VUpper[4],0,6*(VDown[4]-VUpper[4]),src.rows));
Mat roi09 = src(Rect(6*VUpper[8],0,6*(VDown[8]-VUpper[8]),src.rows));
cvtColor(roi05,roi05,CV_BGR2GRAY);
cvtColor(roi09,roi09,CV_BGR2GRAY);
threshold(roi05,roi05,100,255,THRESH_OTSU);
threshold(roi09,roi09,100,255,THRESH_OTSU);
threshold(roi05,roi05,0,255,THRESH_BINARY_INV);
threshold(roi09,roi09,0,255,THRESH_BINARY_INV);
std::vector<std::vector<cv::Point>>contours2;
findContours(roi05,contours2,CV_RETR_LIST,CV_CHAIN_APPROX_SIMPLE);
int imax2 = 0;
int imaxcontour2 = -1;
for (int i=0;i<contours2.size();i++)
{
int itmp = contourArea(contours2);
if (imaxcontour2 < itmp )
{
imax2 = i;
imaxcontour2 = itmp;
}
}
Rect boundRect2;//最小外接矩形
boundRect2 = boundingRect(Mat(contours2[imax2]));
if (boundRect2.y+boundRect2.height >750)
{
//printf("第5个为打开的\n");
result[4] = 0;
}
else
{
//printf("第5个为关闭的\n");
result[4] = 1;
}
contours2.clear();
findContours(roi09,contours2,CV_RETR_LIST,CV_CHAIN_APPROX_SIMPLE);
imax2 = 0;
imaxcontour2 = -1;
for (int i=0;i<contours2.size();i++)
{
int itmp = contourArea(contours2);
if (imaxcontour2 < itmp )
{
imax2 = i;
imaxcontour2 = itmp;
}
}
boundRect2 = boundingRect(Mat(contours2[imax2]));
if (boundRect2.y+boundRect2.height >750)
{
//printf("第9个为打开的\n");
result[8] = 0;
}
else
{
//printf("第9个为关闭的\n");
result[8] = 1;
}
3.2倾斜情况下,条码识别错误
受到摄像头分辨率的限制,使得图像中条形码在倾斜的时候,受到插值算法的影响,边缘变得模糊。虽然尝试了许多方法,但是都无法达到
能够让zxing识别的程度。这个问题不知道哪位有更好的方法,如果可以的话,希望能够告之。
四、系统集成:
由于目前还没有很好地将zxing集成到mfc的环境中来。由于我对“csharp通过dll方式调用console程序”比较熟悉,所以这里尝试采用的是"csharp通过程序调用console的形式"。也就是主要图像处理的部分还是写的console程序,并且运算出相应的结果和图片,而后在csharp的程序中合并得到最后的结果。过程中发现这种方法的问题还是比较多的,包括参数的传递、程序重复运行时的控制等,应该说不是一种很成熟的方法,在以后面对类似的问题的时候,最好是能够直接将代码集成到mfc中,否则就要采用“csharp通过dll方式调用console程序”的方式。
最后的结果如下,并且可以多次测试都没有问题:
五、设计小结:
工作完成了,那么除了对代码进行重构并且提取出可以被重复使用的函数外,对于思路的小结也非常重要。在本例中:
5.1 提出了具有创造性的一个想法:采取分析下面的字符牌是否被遮挡的方式来判断开关闭合情况。逆向思维取得了稳定的结果;
5.2 对于色彩空间转换、对于投影的灵活运用构成了识别的主体。
不足的地方
5.3 对于一维/二维码识别没有构建稳定的库或解决方案,现在使用的zxing可以解决一部分问题,但是不过不了解原理,遇到不能解决的问题就无法继续优化;目前提取条码的方法应该被提出出来。
5.4 验证了"csharp通过程序调用console的形式"是不合算的。