如何使用emgu CV找到与图像中的任意角度的旋转一个黑色的方形 [英] How to find a black square with any angle of rotation in the image using emgu cv
问题描述
我需要找到三个黑色方块的坐标在测试形式。我把示例代码从网站emgu.com并略有变化,但他没有找到我需要什么。图像的尺寸为A4,并且测试形式的尺寸A5。我希望对你有所帮助:)
我差点忘了,广场30像素的大小。
I need to find the coordinates of three black squares in the test form. I took the example code from the site emgu.com and slightly changed it, but he does not find what I need. The size of image is A4, and the size of the test form is A5. I am hope for your help :) I nearly forgot, the size of squares 30 pixels.
private void DetectRectangles(Image<Gray, byte> img)
{
var size = new Size(3, 3);
CvInvoke.GaussianBlur(img, img, size, 0);
CvInvoke.AdaptiveThreshold(img, img, 255, AdaptiveThresholdType.MeanC, ThresholdType.Binary, 75, 100);
UMat cannyEdges = new UMat();
CvInvoke.Canny(img, cannyEdges, 180, 120);
var boxList = new List<RotatedRect>();
using (VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint())
{
CvInvoke.FindContours(cannyEdges, contours, null, RetrType.Tree, ChainApproxMethod.ChainApproxSimple);
int count = contours.Size;
for (int i = 0; i < count; i++)
{
using (VectorOfPoint contour = contours[i])
using (VectorOfPoint approxContour = new VectorOfPoint())
{
CvInvoke.ApproxPolyDP(contour, approxContour, CvInvoke.ArcLength(contour, true) * 0.05, true);
var area = CvInvoke.ContourArea(approxContour);
if (area > 800 && area < 1000)
{
if (approxContour.Size == 4)
{
bool isRectangle = true;
Point[] pts = approxContour.ToArray();
LineSegment2D[] edges = PointCollection.PolyLine(pts, true);
for (int j = 0; j < edges.Length; j++)
{
double angle = Math.Abs(edges[(j + 1) % edges.Length].GetExteriorAngleDegree(edges[j]));
if (angle < 75 || angle > 94)
{
isRectangle = false;
break;
}
}
if (isRectangle)
boxList.Add(CvInvoke.MinAreaRect(approxContour));
}
}
}
}
}
var resultimg = new Image<Bgr,byte>(img.Width, img.Height);
CvInvoke.CvtColor(img, resultimg, ColorConversion.Gray2Bgr);
foreach (RotatedRect box in boxList)
{
CvInvoke.Polylines(resultimg, Array.ConvertAll(box.GetVertices(), Point.Round), true, new Bgr(Color.Red).MCvScalar, 2);
}
imageBox1.Image = resultimg;
resultimg.Save("result_img.jpg"); }
输入图像:
Input image:
推荐答案
由于你正在寻找一个非常特殊的对象,可以使用下面的算法:
Since you are looking for a very specific object, you can use the following algorithm:
- 反转的形象,使前景变为白色,并背景黑色。
- 找到连接组件
-
对于每个轮廓
- Invert the image, so that the foreground becomes white, and the background black.
- Find contours of connected components
For each contours
一。计算的最小面积的矩形箱
a. Compute the minimum area rectangle box
乙。计算箱
面积:巴里亚
℃。计算轮廓的区域: CAREA
c. Compute the area of the contour: carea
Ð。涂一些约束,以确保您的轮廓就是你要找的方
d. Apply some constraint to be sure your contour is the square you're looking for
步骤3d的约束条件是:
The constraints of step 3d are:
-
比
巴里亚/ CAREA
应该是很高的(假设较高那么0.9),这意味着轮廓属于一个的几乎的矩形一滴。
The ratio
barea / carea
should be high (let's say higher then 0.9), meaning that the contour belongs to an almost rectangular blob.
的宽高比箱
应的几乎的1,这意味着箱
基本上是一个方形
The aspect ratio of box
should be almost 1, meaning that the box
is basically a square
广场的大小应该是几乎 30
,拒绝图像中的其它更小或更大的正方形。
The size of the square should be almost 30
, to reject other smaller or bigger squares in the image.
我得到运行这样的结果是:
The result I get running this is:
下面是代码。对不起,这是C ++,但因为它是所有OpenCV的函数调用,你应该能够将它移植容易C#。至少,你可以用它作为参考:
Here is the code. Sorry, it's C++, but since it's all OpenCV function calls you should be able to port it easily to C#. At least, you can use it as a reference:
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main()
{
// Load image
Mat1b img = imread("path_to_image", IMREAD_GRAYSCALE);
// Create the output image
Mat3b out;
cvtColor(img, out, COLOR_GRAY2BGR);
// Create debug image
Mat3b dbg = out.clone();
// Binarize (to remove jpeg arifacts)
img = img > 200;
// Invert image
img = ~img;
// Find connected components
vector<vector<Point>> contours;
findContours(img.clone(), contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
vector<RotatedRect> squares;
// For each contour
for (int i = 0; i < contours.size(); ++i)
{
// Find rotated bounding box
RotatedRect box = minAreaRect(contours[i]);
// Compute the area of the contour
double carea = contourArea(contours[i]);
// Compute the area of the box
double barea = box.size.area();
// Constraint #1
if ((carea / barea) > 0.9)
{
drawContours(dbg, contours, i, Scalar(0, 0, 255), 7);
// Constraint #2
if (min(box.size.height, box.size.width) / max(box.size.height, box.size.width) > 0.95)
{
drawContours(dbg, contours, i, Scalar(255, 0, 0), 5);
// Constraint #3
if (box.size.width > 25 && box.size.width < 35)
{
drawContours(dbg, contours, i, Scalar(0, 255, 0), 3);
// Found the square!
squares.push_back(box);
}
}
}
// Draw output
for (int i = 0; i < squares.size(); ++i)
{
Point2f pts[4];
squares[i].points(pts);
for (int j = 0; j < 4; ++j)
{
line(out, pts[j], pts[(j + 1) % 4], Scalar(0,255,0), 5);
}
}
}
// Resize for better visualization
resize(out, out, Size(), 0.25, 0.25);
resize(dbg, dbg, Size(), 0.25, 0.25);
// Show images
imshow("Steps", dbg);
imshow("Result", out);
waitKey();
return 0;
}
这篇关于如何使用emgu CV找到与图像中的任意角度的旋转一个黑色的方形的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!