C# 扫描图像以查找矩形
我正在尝试扫描一个恒定大小的图像,并找到其中绘制的矩形。 矩形可以有任何大小,但只有红色 这不是问题开始的地方 我将使用一个已经编写好的函数,稍后在代码逻辑中将其用作伪代码调用C# 扫描图像以查找矩形,c#,algorithm,image-processing,computer-vision,C#,Algorithm,Image Processing,Computer Vision,我正在尝试扫描一个恒定大小的图像,并找到其中绘制的矩形。 矩形可以有任何大小,但只有红色 这不是问题开始的地方 我将使用一个已经编写好的函数,稍后在代码逻辑中将其用作伪代码调用 矩形定位(矩形扫描区域)//扫描给定扫描区域中的矩形。 如果未找到Rectage,则返回null 我的逻辑是这样的: 使用带有完整图像大小作为参数的Locate()函数查找第一个初始红色矩形。 现在,划分其余区域,并继续递归扫描。 该算法逻辑的要点是,您从不检查已检查的区域,并且您不必使用任何条件,因为scanArea参
矩形定位(矩形扫描区域)代码>//扫描给定扫描区域中的矩形。
如果未找到Rectage,则返回null
我的逻辑是这样的:
使用带有完整图像大小作为参数的Locate()
函数查找第一个初始红色矩形。
现在,划分其余区域,并继续递归扫描。
该算法逻辑的要点是,您从不检查已检查的区域,并且您不必使用任何条件,因为scanArea
参数始终是一个您以前从未扫描过的新区域(这要感谢分割技术)。
分割过程如下:当前找到的矩形的右侧区域、底部区域和左侧区域
这里有一张图片说明了这个过程。
(白色虚线矩形和黄色箭头不是图像的一部分,我添加它们只是为了演示。)
如您所见,一旦找到一个红色矩形,我会一直扫描它的右侧、底部和左侧。递归地
下面是该方法的代码:
List<Rectangle> difList=new List<Rectangle>();
private void LocateDifferences(Rectangle scanArea)
{
Rectangle foundRect = Locate(scanArea);
if (foundRect == null)
return; // stop the recursion.
Rectangle rightArea = new Rectangle(foundRect.X + foundRect.Width, foundRect.Y, (scanArea.X + scanArea.Width) - (foundRect.X + foundRect.Width), (scanArea.Y + scanArea.Height) - (foundRect.Y + foundRect.Height)); // define right area.
Rectangle bottomArea = new Rectangle(foundRect.X, foundRect.Y + foundRect.Height, foundRect.Width, (scanArea.Y + scanArea.Height) - (foundRect.Y + foundRect.Height)); // define bottom area.
Rectangle leftArea = new Rectangle(scanArea.X, foundRect.Y, (foundRect.X - scanArea.X), (scanArea.Y + scanArea.Height) - (foundRect.Y + foundRect.Height)); // define left area.
difList.Add(rectFound);
LocateDifferences(rightArea);
LocateDifferences(bottomArea);
LocateDifferences(leftArea);
}
List difList=new List();
专用空心位置差异(矩形扫描区域)
{
矩形foundRect=定位(扫描区域);
if(foundRect==null)
return;//停止递归。
矩形rightArea=新矩形(foundRect.X+foundRect.Width,foundRect.Y,(scanArea.X+scanArea.Width)-(foundRect.X+foundRect.Width),(scanArea.Y+scanArea.Height)-(foundRect.Y+foundRect.Height));//定义右侧区域。
矩形底部区域=新矩形(foundRect.X,foundRect.Y+foundRect.Height,foundRect.Width,(scanArea.Y+scanArea.Height)-(foundRect.Y+foundRect.Height));//定义底部区域。
矩形左区域=新矩形(scanArea.X,foundRect.Y,(foundRect.X-scanArea.X),(scanArea.Y+scanArea.Height)-(foundRect.Y+foundRect.Height));//定义左区域。
difList.Add(rectFound);
位置差异(右侧区域);
位置差异(底部区域);
位置差异(左侧区域);
}
到目前为止,一切正常,它确实找到了每个红色矩形。
但有时,矩形保存为几个矩形。原因对我来说是显而易见的:
重叠矩形的大小写。
一个有问题的案例,例如:
现在,在程序中,程序按计划找到第一个红色区域,但是,由于右区域只在第二个区域的中间开始,所以它不会从第二个红色矩形开始扫描。p>
以类似的方式,我可以划分区域,以便底部区域从
scanArea
的开始一直延伸到结尾,如下所示:
但是现在,我们在扫描foundRect
矩形的右侧和左侧的重叠矩形时会遇到问题,例如,在这种情况下:
我只需要得到一个矩形。
我希望结合我的代码逻辑得到任何帮助或建议,因为它工作得很好,但我认为在递归方法中只需要一个或两个附加条件。我不知道该做什么,我真的很感激任何帮助
如果有什么不清楚的地方,就告诉我,我会尽可能地解释!
谢谢
当然,这不是我面临的真正问题,它只是一个小演示,可以帮助我解决我正在处理的真正问题(这是一个实时互联网项目)。我很抱歉,但我没有阅读你的解决方案,因为我不确定你是否想要一个好的解决方案,或者用这个解决方案解决问题
使用现有构建块(如OpenCV,我不知道是否有c#的端口)的简单解决方案是:
以红色通道为例(因为您说过只想检测红色矩形)
findContours
对于每个轮廓
3.1以其边界框为例
3.2通过将轮廓的总面积与边框的总面积进行比较,检查轮廓是否为矩形
解决方案将根据输入图像的不同而变化。
我希望我能帮助你。如果没有,请告诉我您需要什么样的帮助。按照您的标准,不更改Locate()函数,只扩展现有逻辑,我们需要在扫描后加入任何rects。试试这个:
首先稍微修改LocateDifferences()函数,以跟踪可能需要连接的矩形
private void LocateDifferences(Rectangle scanArea)
{
Rectangle foundRect = Locate(scanArea);
if (foundRect == null)
return; // stop the recursion.
Rectangle rightArea = new Rectangle(foundRect.X + foundRect.Width, foundRect.Y, (scanArea.X + scanArea.Width) - (foundRect.X + foundRect.Width), (scanArea.Y + scanArea.Height) - (foundRect.Y + foundRect.Height)); //define right area.
Rectangle bottomArea = new Rectangle(foundRect.X, foundRect.Y + foundRect.Height, foundRect.Width, (scanArea.Y + scanArea.Height) - (foundRect.Y + foundRect.Height)); // define bottom area.
Rectangle leftArea = new Rectangle(scanArea.X, foundRect.Y, (foundRect.X - scanArea.X), (scanArea.Y + scanArea.Height) - (foundRect.Y + foundRect.Height)); // define left area.
if (foundRect.X == scanArea.X || foundRect.Y == scanArea.Y || (foundRect.X + foundRect.Width == scanArea.X + scanArea.Width) || (foundRect.Y + foundRect.Height == scanArea.Y + scanArea.Height))
{
// edge may extend scanArea
difList.Add(Tuple.Create(foundRect, false));
} else {
difList.Add(Tuple.Create(foundRect, true));
}
LocateDifferences(rightArea);
LocateDifferences(bottomArea);
LocateDifferences(leftArea);
}
我还添加了以下两种使用方法:
// JoinRects: will return a rectangle composed of r1 and r2.
private Rectangle JoinRects(Rectangle r1, Rectangle r2)
{
return new Rectangle(Math.Min(r1.X, r2.X),
Math.Min(r1.Y, r2.Y),
Math.Max(r1.Y + r1.Width, r2.Y + r2.Width),
Math.Max(r1.X + r1.Height, r2.X + r2.Height));
}
// ShouldJoinRects: determines if the rectangles are connected and the height or width matches.
private bool ShouldJoinRects(Rectangle r1, Rectangle r2)
{
if ((r1.X + r1.Width + 1 == r2.X && r1.Y == r2.Y && r1.Height == r2.Height)
|| (r1.X - 1 == r2.x + r2.Width && r1.Y == r2.Y && r1.Height == r2.Height)
|| (r1.Y + r1.Height + 1 == r2.Y && r1.X == r2.X && r1.Width == r2.Width)
|| (r1.Y - 1 == r2.Y + r2.Height && r1.X == r2.X && r1.Width == r2.Width))
{
return true;
}
else
{
return false;
}
}
最后是启动扫描的主要功能
List<Tuple<Rectangle, Bool>> difList = new List<Tuple<Rectangle, Bool>();
// HERE: fill our list by calling LocateDifferences
LocateDifferences();
var allGood = difList.Where(t => t.Item2 == true).ToList();
var checkThese = difList.Where(t => t.Item2 == false).ToArray();
for (int i = 0; i < checkThese.Length - 1; i++)
{
// check that its not an empty Rectangle
if (checkThese[i].IsEmpty == false)
{
for (int j = i; j < checkThese.Length; j++)
{
// check that its not an empty Rectangle
if (checkThese[j].IsEmpty == false)
{
if (ShouldJoinRects(checkThese[i], checkThese[j])
{
checkThese[i] = JoinRects(checkThese[i], checkThese[j]);
checkThese[j] = new Rectangle(0,0,0,0);
j = i // restart the inner loop in case we are dealing with a rect that crosses 3 scan areas
}
}
}
allGood.Add(checkThese[i]);
}
}
//Now 'allGood' contains all the rects joined where needed.
List difList=new List t.Item2==true).ToList();
var checkthises=difList.Where(t=>t.Item2==false).ToArray();
对于(int i=0;i
使用以下简单算法的最简单方法:
function find(Image): Collection of Rects
core_rect = FindRects(Image)
split(core_rect) -> 4 rectangles (left-top, left-bottom, right-top, right-bottom)
return Merge of (find(leftTop), find(leftBottom), ...)
function findAll(Image): Collection of Rects
rects <- find(Image)
sort rectangles by X, Y
merge rectangles
sort rectangles by Y, X
merge rectangles
return merged set
函数查找(图像):矩形集合
core_rect=FindRects(图像)
拆分(核心矩形)->4个矩形(左上、左下、右
internal enum Side : byte
{
Left,
Bottom,
Right
}
internal class RectangleInfo
{
public RectangleInfo(Rectangle rect, bool leftOverlap, bool rightOverlap)
{
Rectangle = rect;
LeftOverlap = leftOverlap;
RightOverlap = rightOverlap;
}
public Rectangle Rectangle { get; set; }
public bool LeftOverlap { get; set; }
public bool RightOverlap { get; set; }
}
List<Rectangle> difList = new List<Rectangle>();
List<Rectangle> leftList = new List<Rectangle>();
List<RectangleInfo> bottomList = new List<RectangleInfo>();
List<Rectangle> rightList = new List<Rectangle>();
private void AccumulateDifferences(Rectangle scanArea, Side direction)
{
Rectangle foundRect = Locate(scanArea);
if (foundRect == null)
return; // stop the recursion.
switch (direction)
{
case Side.Left:
if (foundRect.X + foundRect.Width == scanArea.X + scanArea.Width)
leftList.Add(foundRect);
else difList.Add(foundRect);
break;
case Side.Bottom:
bottomList.Add(new RectangleInfo(foundRect, foundRect.X == scanArea.X, foundRect.X + foundRect.Width == scanArea.X + scanArea.Width));
break;
case Side.Right:
if (foundRect.X == scanArea.X)
rightList.Add(foundRect);
else difList.Add(foundRect);
break;
}
Rectangle leftArea = new Rectangle(scanArea.X, foundRect.Y, (foundRect.X - scanArea.X), (scanArea.Y + scanArea.Height) - (foundRect.Y + foundRect.Height)); // define left area.
Rectangle bottomArea = new Rectangle(foundRect.X, foundRect.Y + foundRect.Height, foundRect.Width, (scanArea.Y + scanArea.Height) - (foundRect.Y + foundRect.Height)); // define bottom area.
Rectangle rightArea = new Rectangle(foundRect.X + foundRect.Width, foundRect.Y, (scanArea.X + scanArea.Width) - (foundRect.X + foundRect.Width), (scanArea.Y + scanArea.Height) - (foundRect.Y + foundRect.Height)); //define right area.
AccumulateDifferences(leftArea, Side.Left);
AccumulateDifferences(bottomArea, Side.Bottom);
AccumulateDifferences(rightArea, Side.Right);
}
private void ProcessDifferences()
{
foreach (RectangleInfo rectInfo in bottomList)
{
if (rectInfo.LeftOverlap)
{
Rectangle leftPart =
leftList.Find(r => r.X + r.Width == rectInfo.Rectangle.X
&& r.Y == rectInfo.Rectangle.Y
&& r.Height == rectInfo.Rectangle.Height
);
if (leftPart != null)
{
rectInfo.Rectangle.X = leftPart.X;
leftList.Remove(leftPart);
}
}
if (rectInfo.RightOverlap)
{
Rectangle rightPart =
rightList.Find(r => r.X == rectInfo.Rectangle.X + rectInfo.Rectangle.Width
&& r.Y == rectInfo.Rectangle.Y
&& r.Height == rectInfo.Rectangle.Height
);
if (rightPart != null)
{
rectInfo.Rectangle.X += rightPart.Width;
rightList.Remove(rightPart);
}
}
difList.Add(rectInfo.Rectangle);
}
difList.AddRange(leftList);
difList.AddRange(rightList);
}
private void LocateDifferences(Rectangle scanArea)
{
AccumulateDifferences(scanArea, Side.Left);
ProcessDifferences();
leftList.Clear();
bottomList.Clear();
rightList.Clear();
}
unfinished: {10,13,1}
unfinished: {10,13,1},{16,18,2}
unfinished: {1,4,3},{6,7,3},{10,13,1},{16,18,2},{21,214}
unfinished: {1,4,3},{6,7,3},{16,18,2},{21,21,4}
finished: {10,13,1,5}
unfinished: {12,16,7}
finished: {10,13,1,5},{16,18,2,5},{1,4,3,6},{6,7,3,8},{21,21,4,8}
unfinished:
finished: {10,13,1,5},{16,18,2,5},{1,4,3,6},{6,7,3,8},{21,21,4,8},
{12,16,7,10},{3,10,10,13},{13,17,13,14},{19,22,11,14}