哈工大博士王刚毅论文中提到红孔检测法,论文描述其检测效果很好,用opencv实现了一下可能是他描述的不够详细,也可能本人理解有偏差,实现方法不一致,导致我的检测效果很一般。
// Blue.cpp : 定义控制台应用程序的入口点。
//
//
#include "stdafx.h"
#include <opencv/cv.h>
#include <opencv/cxcore.h>
#include <opencv/highgui.h>
#include <cmath>
#include <iostream>
#include<vector>
#include <imgproc/imgproc.hpp>
using namespace std;
using namespace cv;
#define pi 3.1415926
int _tmain(int argc, _TCHAR* argv[])
{
Mat img =imread("D://转移//交通标志//交通标志数据库//TEMP1//00100.jpg");
if (!img.data)
{
return 0;
}
/*cvNamedWindow("test");
imshow("test",img);
cvWaitKey(0);*/
//转到HSV
Mat hsv_base;
Mat how_red;
cvtColor(img, hsv_base, CV_BGR2HSV );
/*cvNamedWindow("hsv");
imshow("hsv",hsv_base);
cvWaitKey(0);*/
Mat colorCut;
colorCut.create(img.rows,img.cols,CV_32F);
how_red.create(img.rows,img.cols,CV_32F);
//颜色分割
for(int x=0;x<hsv_base.rows;x++)
{
for(int y=0;y<hsv_base.cols;y++)
{
double h_src=hsv_base.at<Vec3b >(x,y)[0];
h_src =h_src/255.0*360;
double s_src=hsv_base.at<Vec3b >(x,y)[1];
s_src=s_src/255;
double v_src= hsv_base.at<Vec3b >(x,y)[2];
if ( h_src>=300&&h_src<360)
{
how_red.at<float>(x,y)=s_src*sin((h_src-300.0)/180.0*pi)/sin(60.0/180*pi);
}
else if (h_src>=0&&h_src<=60)
{
how_red.at<float>(x,y)=s_src*sin((60.0-h_src)/180.0*pi)/sin(60.0/180*pi);
}
else
{
how_red.at<float>(x,y)=0.0;
}
colorCut.at<float>(x,y)=0;
if (h_src>330||(h_src<=30&&s_src>=0.2))
{
colorCut.at<float>(x,y)=255;
}
}
}
double *max_value ;
double *min_value ;
double maxVal=0;
double minVal =0;
max_value =&maxVal;
min_value =&minVal;
minMaxLoc(how_red, min_value, max_value);
/*cvNamedWindow("how");
imshow("how",how_red);
cvWaitKey(0);*/
//////////////////////////////////////////////////////////////////////////
//红色位图均值滤波//
//红色程度图滤波//
Mat blueredImg ;
Mat blueredHowRed;
blueredImg.create(colorCut.rows,colorCut.cols,CV_32F);
blueredHowRed.create(colorCut.rows,colorCut.cols,CV_32F);
colorCut/=255.;
blur(colorCut,blueredImg,Size(7,7));
minMaxLoc(blueredImg, min_value, max_value);
blur(how_red,blueredHowRed,Size(7,7));
//cvNamedWindow("blur");
//imshow("blur",blueredImg);
//cvWaitKey(0);
//////////////////////////////////////////////////////////////////////////
//得到最终细化后要提取区域的图像
Mat RefinedImg(colorCut.rows,colorCut.cols,CV_8UC1);
for (int x =0;x<img.rows;x++)
{
for (int y=0;y<img.cols;y++)
{
double f =blueredHowRed.at<float>(x,y);
double r = blueredImg.at<float>(x,y);
double ff =how_red.at<float>(x,y);
if (r>=0.8)
{
RefinedImg.at<uchar>(x,y)=255;
}
else if (ff>=f&& r<0.8&&r>=0.2)
{
RefinedImg.at<uchar>(x,y)=255;
}
else
{
RefinedImg.at<uchar>(x,y)=0;
}
}
}
cvNamedWindow("last");
imshow("last",RefinedImg);
cvWaitKey(0);
imwrite("RefinedImg.jpg",RefinedImg);
//////////////////////////////////////////////////////////////////////////
//开闭运算//
dilate(RefinedImg,RefinedImg,cv::Mat());
erode(RefinedImg,RefinedImg,cv::Mat());
//dilate(RefinedImg,RefinedImg,cv::Mat());
cvNamedWindow("bbbb");
imshow("bbbb",RefinedImg);
cvWaitKey(0);
//////////////////////////////////////////////////////////////////////////
//提取区域寻找红孔//
vector<vector<Point>> contours;
findContours(RefinedImg,
contours, // a vector of contours
CV_RETR_EXTERNAL, // retrieve the external contours
CV_CHAIN_APPROX_NONE); // retrieve all pixels of each contours
//筛选区域,太大的太小的去除//
Mat resultt(colorCut.rows,colorCut.cols,CV_8U,Scalar(0));
int cmin= 100; // minimum contour length
int cmax= 1000; // maximum contour length
vector<vector<Point>>::const_iterator itc= contours.begin();
while (itc!=contours.end()) {
if (itc->size() < cmin || itc->size() > cmax)
itc= contours.erase(itc);
else
++itc;
}
//////////////////////////////////////////////////////////////////////////
// draw contours on the original image//
//对筛选后的区域求外接多凸边形//
vector<Point> hull;
vector<vector<Point>>::const_iterator itc1=contours.begin();
while (itc1!=contours.end())
{
convexHull(Mat(*itc1),hull);
// Iterate over each segment and draw it
vector<Point>::const_iterator it= hull.begin();
while (it!=(hull.end()-1))
{
line(resultt,*it,*(it+1),Scalar(255),3);
++it;
}
line(resultt,*(hull.begin()),*(hull.end()-1),Scalar(255),3);
++itc1;
}
vector<vector<Point>> contours2;
findContours(resultt,
contours2, // a vector of contours
CV_RETR_EXTERNAL, // retrieve the external contours
CV_CHAIN_APPROX_NONE);
drawContours(resultt,contours2, -1 , Scalar(255),CV_FILLED); //填充区域。//
namedWindow("ddddd");
imshow("ddddd",resultt);
cvWaitKey(0);
minMaxLoc(resultt, min_value, max_value);
cout<<"max:"<<maxVal<<"min:"<<minVal<<endl;
imwrite("resultt.jpg",resultt);
//////////////////////////////////////////////////////////////////////////
//显示红孔
Mat Hole(img.rows,img.cols,CV_8UC1);
Mat res = imread("resultt.jpg",0);
Mat refin= imread("RefinedImg.jpg",0);
for (int x=0;x<img.rows;x++)
{
for (int y=0;y<img.cols;y++)
{
int rr =res.at<uchar>(x,y);
int ff = refin.at<uchar>(x,y);
if (rr>ff)
{
Hole.at<uchar>(x,y)=255;
}
else
{
Hole.at<uchar>(x,y)=0;
}
}
}
erode(Hole,Hole,cv::Mat());
namedWindow("dddd");
imshow("dddd",Hole);
cvWaitKey(0);
return 0;
}
////////////////////////////////////////////////////////////////////////