我在使用opencv 2.4 for Android检测速度交通标志时遇到问题。 我做了以下事情:
"捕获帧 - >将其转换为HSV - >提取红色区域 - >用椭圆检测检测标志"
到目前为止,只要图像质量好,椭圆检测就能完美。 但正如你在下面的图片中看到的那样,红色提取效果不好,因为相框质量差,我认为。
将原始图像转换为HSV:
Imgproc.cvtColor(this.source, this.source, Imgproc.COLOR_RGB2HSV, 3);
提取红色
Core.inRange(this.source, new Scalar(this.h,this.s,this.v), new Scalar(230,180,180), this.source);
所以我的问题是有另一种方法来检测这样的交通标志或从中提取红色区域,顺便说一句,这可能会像上一张图片一样微弱吗?
这是原始图片:
这会转换为HSV,因为您可以看到红色区域看起来与附近的树木颜色相同。多数民众赞成我怎么想知道它的红色但是我不能。
转换为HSV:
这是用红色提取的。如果颜色是正确的,我应该在符号周围得到几乎完美的圆/椭圆,但由于颜色不正确而不完整。
提取后的结果:
椭圆方法:
private void findEllipses(Mat input){
Mat thresholdOutput = new Mat();
int thresh = 150;
List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
MatOfInt4 hierarchy = new MatOfInt4();
Imgproc.threshold(source, thresholdOutput, thresh, 255, Imgproc.THRESH_BINARY);
//Imgproc.Canny(source, thresholdOutput, 50, 180);
Imgproc.findContours(source, contours, hierarchy, Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
RotatedRect minEllipse[] = new RotatedRect[contours.size()];
for(int i=0; i<contours.size();i++){
MatOfPoint2f temp=new MatOfPoint2f(contours.get(i).toArray());
if(temp.size().height > minEllipseSize && temp.size().height < maxEllipseSize){
double a = Imgproc.fitEllipse(temp).size.height;
double b = Imgproc.fitEllipse(temp).size.width;
if(Math.abs(a - b) < 10)
minEllipse[i] = Imgproc.fitEllipse(temp);
}
}
detectedObjects.clear();
for( int i = 0; i< contours.size(); i++ ){
Scalar color = new Scalar(180, 255, 180);
if(minEllipse[i] != null){
detectedObjects.add(new DetectedObject(minEllipse[i].center));
DetectedObject detectedObj = new DetectedObject(minEllipse[i].center);
Core.ellipse(source, minEllipse[i], color, 2, 8);
}
}
}
答案 0 :(得分:8)
你会发现有两种方法可以达到这个目的:
根据我的经验,我发现基于形状的方法效果很好,因为在不同的光照条件,相机质量等下,颜色可能会发生很大变化。
由于您需要检测速度交通标志,我认为这些交通标志始终是圆形的,您可以使用椭圆检测器查找图像中的所有圆形对象,然后应用一些验证来确定它是否是是否有交通标志。
为什么要进行椭圆检测?
好吧,既然你正在寻找透视扭曲的圆圈,你实际上在寻找椭圆。实时椭圆检测是一个有趣(虽然有限)的研究课题。我将向您发表2篇提供C ++源代码的论文(您可以通过本机JNI调用在您的app中使用):
升。 Libuda,I。Grothues,K.-F。 Kraiss,数字图像中的椭圆检测 使用几何特征的数据,在:J. Braz,A。Ranchordas,H。Arajo, J. Jorge(编辑),计算机图形学与计算机视觉进展, 计算机与信息科学通讯第4卷, Springer Berlin Heidelberg,2007,pp.229-239。 link,code
微米。 Fornaciari,A。Prati,R。Cucchiara, “用于嵌入式视觉应用的快速有效的椭圆探测器”,模式识别,2014 link,code
<强>更新强>
我尝试了方法2)而没有任何预处理。您可以看到至少检测到带有红色边框的标志非常好:
答案 1 :(得分:4)
参考您的文字:
这会转换为HSV,因为您可以看到红色区域看起来颜色相同 如附近的树木。多数民众赞成我怎么想知道它的红色但是我不能。
我想告诉你我的结果基本上你做了什么(简单的操作应该很容易转移到android openCV):
// convert to HSV
cv::Mat hsv;
cv::cvtColor(input,hsv,CV_BGR2HSV);
std::vector<cv::Mat> channels;
cv::split(hsv,channels);
// opencv = hue values are divided by 2 to fit 8 bit range
float red1 = 25/2.0f;
// red has one part at the beginning and one part at the end of the range (I assume 0° to 25° and 335° to 360°)
float red2 = (360-25)/2.0f;
// compute both thresholds
cv::Mat thres1 = channels[0] < red1;
cv::Mat thres2 = channels[0] > red2;
// choose some minimum saturation
cv::Mat saturationThres = channels[1] > 50;
// combine the results
cv::Mat redMask = (thres1 | thres2) & saturationThres;
// display result
cv::imshow("red", redMask);
这些是我的结果:
根据您的结果,请注意findContours
改变输入图像,因此如果您在findContours之后保存图像,也许您已经提取了椭圆,但只是不再在图像中看到它。
答案 2 :(得分:1)
private void findEllipses(Mat input){
Mat thresholdOutput = new Mat();
int thresh = 150;
List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
MatOfInt4 hierarchy = new MatOfInt4();
Imgproc.threshold(source, thresholdOutput, thresh, 255, Imgproc.THRESH_BINARY);
//Imgproc.Canny(source, thresholdOutput, 50, 180);
Imgproc.findContours(source, contours, hierarchy, Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
// source = thresholdOutput;
RotatedRect minEllipse[] = new RotatedRect[contours.size()];
for(int i=0; i<contours.size();i++){
MatOfPoint2f temp=new MatOfPoint2f(contours.get(i).toArray());
if(temp.size().height > minEllipseSize && temp.size().height < maxEllipseSize){
double a = Imgproc.fitEllipse(temp).size.height;
double b = Imgproc.fitEllipse(temp).size.width;
if(Math.abs(a - b) < 10)
minEllipse[i] = Imgproc.fitEllipse(temp);
}
}
detectedObjects.clear();
for( int i = 0; i< contours.size(); i++ ){
Scalar color = new Scalar(180, 255, 180);
if(minEllipse[i] != null){
detectedObjects.add(new DetectedObject(minEllipse[i].center));
DetectedObject detectedObj = new DetectedObject(minEllipse[i].center);
Core.ellipse(source, minEllipse[i], color, 2, 8);
}
}
}
答案 3 :(得分:1)