我正在尝试检测在图像上绘制的一些矩形(白色)。 (比如使用油漆或其他图像编辑工具)。 由于我是图像处理的初学者,我通过net和OpenCV示例程序搜索完成了这项工作,但无法让它完美地运行。我正在使用OpenCV C ++库。
我尝试过的算法
cv::Mat src = cv::imread(argv[1]);
cv::Mat gray;
cv::cvtColor(src, gray, CV_BGR2GRAY);
meanStdDev(gray, mu, sigma);
cv::Mat bw;
cv::Canny(gray, bw, mu.val[0] - sigma.val[0], mu.val[0] + sigma.val[0]);
std::vector<std::vector<cv::Point> > contours;
cv::findContours(bw.clone(), contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
std::vector<cv::Point> approx;
for (int i = 0; i < contours.size(); i++){
cv::approxPolyDP(cv::Mat(contours[i]), approx, cv::arcLength(cv::Mat(contours[i]), true)*0.02, true);
if (approx.size() >= 4 && approx.size() <= 6)
Rect boundRect = boundingRect( Mat(approx) );
rectangle( dst, boundRect.tl(), boundRect.br(), Scalar(255,255,255), 1, 8, 0 );}
仅检测到一个矩形。你可以指导一下这个链接吗?
输入图片:
输出图片:
答案 0 :(得分:1)
我无法编译你的代码示例,因为在if-block中声明了boundRect但是矩形绘图(试图访问boundRect)在if-block之外,所以我调整了你的代码:
enum
使用输入图像我得到这个输出:
这可能不是你所期望的。看看canny输出图像(看看可视化调试的中间结果总是好的!),图像中有太多的结构,轮廓将涵盖所有这些,所以有一些将近似于多项式有4到6个元素。
相反,你必须变得更聪明一些。您可以尝试使用cv :: HoughLinesP提取直线并连接这些线。或者您可以尝试通过查找白色区域来分割图像(如果矩形始终为白色)。int main(int argc, char* argv[])
{
cv::Mat src = cv::imread("C:/StackOverflow/Input/rectangles.png");
cv::Mat dst = src.clone();
cv::Mat gray;
cv::cvtColor(src, gray, CV_BGR2GRAY);
// ADDED: missing declaration of mu and sigma
cv::Scalar mu, sigma;
meanStdDev(gray, mu, sigma);
cv::Mat bw;
cv::Canny(gray, bw, mu.val[0] - sigma.val[0], mu.val[0] + sigma.val[0]);
// ADDED: displaying the canny output
cv::imshow("canny", bw);
std::vector<std::vector<cv::Point> > contours;
cv::findContours(bw.clone(), contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
std::vector<cv::Point> approx;
for (int i = 0; i < contours.size(); i++){
cv::approxPolyDP(cv::Mat(contours[i]), approx, cv::arcLength(cv::Mat(contours[i]), true)*0.02, true);
if (approx.size() >= 4 && approx.size() <= 6)
{
// ADDED: brackets around both lines belonging to the if-block
cv::Rect boundRect = cv::boundingRect(cv::Mat(approx));
cv::rectangle(dst, boundRect.tl(), boundRect.br(), cv::Scalar(255, 255, 255), 3, 8, 0);
}
}
// ADDED: displaying input and results
cv::imshow("input", src);
cv::imshow("dst", dst);
cv::imwrite("C:/StackOverflow/Output/rectangles.png", dst);
cv::waitKey(0);
return 0;
}
给出了这个结果:
如您所见,白色附近还有其他明亮区域。多项式近似也没有多大帮助。
答案 1 :(得分:0)
你确定你只找到一个轮廓或者你只是绘制一个轮廓吗?它看起来并不像你在绘图程序中循环所以你只会绘制第一个找到的。
我有一个博客,早已死了,可能会为您提供一些好的指导:http://workingwithcomputervision.blogspot.co.uk/2012/09/game-player-step-2-finding-game-board.html
如果链接死亡,我相信这是与文章轮廓相关的文章中最相关的部分:
//Draw contours
for (int i = 0; i < contours.size(); i++) {
Scalar color = Scalar(0, 255, 0);
drawContours(drawing, contours, i, color, 2, 8, hierarchy, 0, Point());
}
我注意到你正在使用边界矩形进行绘图。这是另一个绘图例程,再次从上面的链接,这样做:
Rect bounds;
Mat drawing = Mat::zeros(purpleOnly.size(), CV_8UC3);
int j = 0;
for (int i = 0; i < contours.size(); i++) {
if (arcLength(contours[i], true) > 500){
Rect temp = boundingRect(contours[i]);
rectangle(drawing, temp, Scalar(255, 0, 0), 2, 8);
if (j == 0) {
bounds = temp;
} else {
bounds = bounds | temp;
}
j++;
}
}
请注意,我还会对轮廓的大小进行一些检查,以滤除噪音。
答案 2 :(得分:0)
通常,在HSV空间中分割颜色(甚至是白色)更容易。有适当的阈值:
inRange(hsv, Scalar(0, 0, 220), Scalar(180, 30, 255), mask);
我们不关心Hue,只保持低饱和度和高价值,我得到:
然后,您可以轻松找到连接的组件,并丢弃小于阈值th_blob_size
的blob。得到的矩形是(绿色):
您最终可以应用其他过滤阶段来解决更困难的情况,但对于此图像,删除小blob就足够了。如果您需要更强大的功能,请发布其他图片。
代码:
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
Mat3b img = imread("path_to_image");
int th_blob_size = 100;
Mat3b hsv;
cvtColor(img, hsv, COLOR_BGR2HSV);
Mat1b mask;
inRange(hsv, Scalar(0, 0, 220), Scalar(180, 30, 255), mask);
vector<vector<Point>> contours;
findContours(mask.clone(), contours, RETR_EXTERNAL, CHAIN_APPROX_NONE);
Mat3b res = img.clone();
for (int i = 0; i < contours.size(); ++i)
{
// Remove small blobs
if (contours[i].size() < th_blob_size)
{
continue;
}
Rect box = boundingRect(contours[i]);
rectangle(res, box, Scalar(0,255,0), 1);
}
imshow("Result", res);
waitKey();
return 0;
}