emgucv处理图像 查找轮廓个数

有时想起 2016-08-25 04:55:15
输入图像经二值后如图所示
现在用的方法是: 检测凸包个数,用Contour<Point>.Convex属性。凸缺陷也试了,用Contour<Point>.GetConvexityDefacts。但是两个查出来的正确率都比较低。有时候13 有时候12 、11、求问有何其他好方法
...全文
637 10 点赞 打赏 收藏 举报
写回复
10 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
qq_39580335 2017-07-21
二值化,凸包,缺陷可以教教我吗,加我1026608284
  • 打赏
  • 举报
回复
有时想起 2016-08-31
引用 8 楼 crystal_lz 的回复:

    rect.Width += 1; rect.Height += 1;
    if (nCount < nPixelMin || nCount > nPixelMax) {
        foreach (var v in lstTemp) {
            this.SetColorFormByColorInfo(v.X, v.Y, Color.White);
        }
        return Rectangle.Empty;
    }
看到上面的图 为什么没有圈出来的地方是白色的 我就觉得奇怪了 然后我刚才突然发现 为什么 里面会有这个循环 这不是脑残了吗 多次一句不说 还浪费时间 浪费的不只是一个循环的时间 由于被设置成了白色 下次遍历到的时候 遇到白色 又会去判断一次 因为我是一行一行遍历的 遇到一个白色 就去找和这个白色连通的像素点 这代码删掉吧 把那个循环注释掉后 我电脑20毫秒左右出结果 不注释 接近200毫秒 我就不知道 当时写代码时候 脑子是不是短路了。。。
嗯 可以的 就是对白块断点的话 判断还是差点 本来一个会圈出2个
  • 打赏
  • 举报
回复
有时想起 2016-08-30
引用 3 楼 crystal_lz 的回复:
你是要白色的个数? 而且你的图都张差不多这个样子 ?
是的 白色个数 图都差不多的 区别就是旋转了 位置不一样罢了
  • 打赏
  • 举报
回复
crystal_lz 2016-08-30

    rect.Width += 1; rect.Height += 1;
    if (nCount < nPixelMin || nCount > nPixelMax) {
        foreach (var v in lstTemp) {
            this.SetColorFormByColorInfo(v.X, v.Y, Color.White);
        }
        return Rectangle.Empty;
    }
看到上面的图 为什么没有圈出来的地方是白色的 我就觉得奇怪了 然后我刚才突然发现 为什么 里面会有这个循环 这不是脑残了吗 多次一句不说 还浪费时间 浪费的不只是一个循环的时间 由于被设置成了白色 下次遍历到的时候 遇到白色 又会去判断一次 因为我是一行一行遍历的 遇到一个白色 就去找和这个白色连通的像素点 这代码删掉吧 把那个循环注释掉后 我电脑20毫秒左右出结果 不注释 接近200毫秒 我就不知道 当时写代码时候 脑子是不是短路了。。。
  • 打赏
  • 举报
回复
crystal_lz 2016-08-30
是的

这个是我 nPixelMin 200 的效果
  • 打赏
  • 举报
回复
有时想起 2016-08-30
引用 5 楼 crystal_lz 的回复:
参照我以前一个验证码识别的帖子 里面的代码 有一个 CodeHelper.cs http://bbs.csdn.net/topics/391905849 注释里面也是有的 可以参照这张图的思路 深度遍历 连续的像素点 这个是我从里面拷贝出来的部分代码 如果按照你的需求 可以去掉一些代码

private void button1_Click(object sender, EventArgs e) {
    Image img = Image.FromFile("./fuck.png");
    List<Rectangle> lstRect = this.GetCharRect(img, 0, int.MaxValue);
    using (Graphics g = this.CreateGraphics()) {
        g.DrawImage(img, 0, 0);
        lstRect.ForEach(r => {
            g.DrawRectangle(Pens.Cyan, r);
        });
    }
}
private BitmapData m_bmpData;
private byte[] m_byColorInfo;
/// <summary>
/// 获取验证码字符所在的区域
/// </summary>
/// <param name="imgDark">二值化后的图像</param>
/// <param name="nPixelMin">连续的最小像素个数 小于此数将被忽略</param>
/// <param name="nPixelMax">连续的最大像素个数 大于此数将被忽略</param>
/// <returns></returns>
public List<Rectangle> GetCharRect(Image imgDark, int nPixelMin, int nPixelMax) {
    Bitmap bmp = (Bitmap)imgDark;
    m_bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
    m_byColorInfo = new byte[bmp.Height * m_bmpData.Stride];
    Marshal.Copy(m_bmpData.Scan0, m_byColorInfo, 0, m_byColorInfo.Length);
    List<Rectangle> lstRect = new List<Rectangle>();
    for (int y = 0, leny = bmp.Height; y < leny; y++) {
        for (int x = 0, lenx = bmp.Width; x < lenx; x++) {
            if (this.GetArgbFormByColor(x, y) == Color.White.ToArgb()) {//【【【注意 你需要的是白色】】】
                Rectangle rectTemp = this.GetRectFromPoint(nPixelMin, nPixelMax, new Point(x, y), Color.White, Color.Magenta);
                if (rectTemp != Rectangle.Empty) lstRect.Add(rectTemp);
            }
        }
    }
    Marshal.Copy(m_byColorInfo, 0, m_bmpData.Scan0, m_byColorInfo.Length);
    bmp.UnlockBits(m_bmpData);
    //将区域按照left属性排序
    for (int i = 0; i < lstRect.Count; i++) {
        for (int j = 1; j < lstRect.Count - i; j++) {
            if (lstRect[j - 1].Left > lstRect[j].Left) {
                Rectangle rectTemp = lstRect[j];
                lstRect[j] = lstRect[j - 1];
                lstRect[j - 1] = rectTemp;
            }
        }
    }
    return lstRect;
}

private Rectangle GetRectFromPoint(int nPixelMin, int nPixelMax, Point ptStart, Color clrSrc, Color clrSet) {
    int nCount = 0;
    int nArgb = clrSrc.ToArgb();
    Rectangle rect = new Rectangle(ptStart.X, ptStart.Y, 0, 0);
    List<Point> ptRegList = new List<Point>();
    List<Point> lstTemp = new List<Point>();
    ptRegList.Add(ptStart);
    lstTemp.Add(ptStart);
    this.SetColorFormByColorInfo(ptStart.X, ptStart.Y, clrSet);
    while (ptRegList.Count != 0) {
        Point ptTemp = this.GetNextPoint(ptRegList[ptRegList.Count - 1], nArgb);
        //Point ptTemp = ptRegList[ptRegList.Count - 1];
        if (ptTemp != Point.Empty) {
            ptRegList.Add(ptTemp);
            lstTemp.Add(ptTemp);
            this.SetColorFormByColorInfo(ptTemp.X, ptTemp.Y, clrSet);
            nCount++;
            if (ptTemp.X < rect.Left) { rect.Width = rect.Right - ptTemp.X; rect.X = ptTemp.X; }
            if (ptTemp.Y < rect.Top) { rect.Height = rect.Bottom - ptTemp.Y; rect.Y = ptTemp.Y; }
            if (ptTemp.X > rect.Right) rect.Width = ptTemp.X - rect.Left;
            if (ptTemp.Y > rect.Bottom) rect.Height = ptTemp.Y - rect.Top;
        } else
            ptRegList.RemoveAt(ptRegList.Count - 1);
    }
    rect.Width += 1; rect.Height += 1;
    if (nCount < nPixelMin || nCount > nPixelMax) {
        foreach (var v in lstTemp) {
            this.SetColorFormByColorInfo(v.X, v.Y, Color.White);
        }
        return Rectangle.Empty;
    }
    return rect;
}

private Point GetNextPoint(Point ptStart, int nArgb) {
    if (m_bmpData.Height > ptStart.Y + 1 && this.GetArgbFormByColor(ptStart.X, ptStart.Y + 1) == nArgb)
        return new Point(ptStart.X, ptStart.Y + 1);
    if (m_bmpData.Width > ptStart.X + 1 && this.GetArgbFormByColor(ptStart.X + 1, ptStart.Y) == nArgb)
        return new Point(ptStart.X + 1, ptStart.Y);
    if (0 <= ptStart.Y - 1 && this.GetArgbFormByColor(ptStart.X, ptStart.Y - 1) == nArgb)
        return new Point(ptStart.X, ptStart.Y - 1);
    if (0 <= ptStart.X - 1 && this.GetArgbFormByColor(ptStart.X - 1, ptStart.Y) == nArgb)
        return new Point(ptStart.X - 1, ptStart.Y);
    if (0 <= ptStart.X - 1 && m_bmpData.Height > ptStart.Y + 1 && this.GetArgbFormByColor(ptStart.X - 1, ptStart.Y + 1) == nArgb)
        return new Point(ptStart.X - 1, ptStart.Y + 1);
    if (m_bmpData.Width > ptStart.X + 1 && m_bmpData.Height > ptStart.Y + 1 && this.GetArgbFormByColor(ptStart.X + 1, ptStart.Y + 1) == nArgb)
        return new Point(ptStart.X + 1, ptStart.Y + 1);
    if (m_bmpData.Width > ptStart.X + 1 && 0 <= ptStart.Y - 1 && this.GetArgbFormByColor(ptStart.X + 1, ptStart.Y - 1) == nArgb)
        return new Point(ptStart.X + 1, ptStart.Y - 1);
    if (0 <= ptStart.X - 1 && 0 <= ptStart.Y - 1 && this.GetArgbFormByColor(ptStart.X - 1, ptStart.Y - 1) == nArgb)
        return new Point(ptStart.X - 1, ptStart.Y - 1);
    return Point.Empty;
}

private int GetArgbFormByColor(int x, int y) {
    return Color.FromArgb(255,
         m_byColorInfo[y * m_bmpData.Stride + x * 3],
         m_byColorInfo[y * m_bmpData.Stride + x * 3 + 1],
         m_byColorInfo[y * m_bmpData.Stride + x * 3 + 2]).ToArgb();
}

private void SetColorFormByColorInfo(int x, int y, Color clr) {
    m_byColorInfo[y * m_bmpData.Stride + x * 3] = clr.B;
    m_byColorInfo[y * m_bmpData.Stride + x * 3 + 1] = clr.G;
    m_byColorInfo[y * m_bmpData.Stride + x * 3 + 2] = clr.R;
}
测试了 很好用 识别率也可以 就是这个nPixelMin参数好像效果看不出 我试着慢慢加大。主要有一些图片白块连接的地方有点断。出来的效果其实是一个白块 但会误识别两个。是应该调整这里的nPixelMin参数么???
  • 打赏
  • 举报
回复
crystal_lz 2016-08-30

参照我以前一个验证码识别的帖子 里面的代码 有一个 CodeHelper.cs
http://bbs.csdn.net/topics/391905849
注释里面也是有的

可以参照这张图的思路 深度遍历 连续的像素点
这个是我从里面拷贝出来的部分代码 如果按照你的需求 可以去掉一些代码

private void button1_Click(object sender, EventArgs e) {
Image img = Image.FromFile("./fuck.png");
List<Rectangle> lstRect = this.GetCharRect(img, 0, int.MaxValue);
using (Graphics g = this.CreateGraphics()) {
g.DrawImage(img, 0, 0);
lstRect.ForEach(r => {
g.DrawRectangle(Pens.Cyan, r);
});
}
}
private BitmapData m_bmpData;
private byte[] m_byColorInfo;
/// <summary>
/// 获取验证码字符所在的区域
/// </summary>
/// <param name="imgDark">二值化后的图像</param>
/// <param name="nPixelMin">连续的最小像素个数 小于此数将被忽略</param>
/// <param name="nPixelMax">连续的最大像素个数 大于此数将被忽略</param>
/// <returns></returns>
public List<Rectangle> GetCharRect(Image imgDark, int nPixelMin, int nPixelMax) {
Bitmap bmp = (Bitmap)imgDark;
m_bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
m_byColorInfo = new byte[bmp.Height * m_bmpData.Stride];
Marshal.Copy(m_bmpData.Scan0, m_byColorInfo, 0, m_byColorInfo.Length);
List<Rectangle> lstRect = new List<Rectangle>();
for (int y = 0, leny = bmp.Height; y < leny; y++) {
for (int x = 0, lenx = bmp.Width; x < lenx; x++) {
if (this.GetArgbFormByColor(x, y) == Color.White.ToArgb()) {//【【【注意 你需要的是白色】】】
Rectangle rectTemp = this.GetRectFromPoint(nPixelMin, nPixelMax, new Point(x, y), Color.White, Color.Magenta);
if (rectTemp != Rectangle.Empty) lstRect.Add(rectTemp);
}
}
}
Marshal.Copy(m_byColorInfo, 0, m_bmpData.Scan0, m_byColorInfo.Length);
bmp.UnlockBits(m_bmpData);
//将区域按照left属性排序
for (int i = 0; i < lstRect.Count; i++) {
for (int j = 1; j < lstRect.Count - i; j++) {
if (lstRect[j - 1].Left > lstRect[j].Left) {
Rectangle rectTemp = lstRect[j];
lstRect[j] = lstRect[j - 1];
lstRect[j - 1] = rectTemp;
}
}
}
return lstRect;
}

private Rectangle GetRectFromPoint(int nPixelMin, int nPixelMax, Point ptStart, Color clrSrc, Color clrSet) {
int nCount = 0;
int nArgb = clrSrc.ToArgb();
Rectangle rect = new Rectangle(ptStart.X, ptStart.Y, 0, 0);
List<Point> ptRegList = new List<Point>();
List<Point> lstTemp = new List<Point>();
ptRegList.Add(ptStart);
lstTemp.Add(ptStart);
this.SetColorFormByColorInfo(ptStart.X, ptStart.Y, clrSet);
while (ptRegList.Count != 0) {
Point ptTemp = this.GetNextPoint(ptRegList[ptRegList.Count - 1], nArgb);
//Point ptTemp = ptRegList[ptRegList.Count - 1];
if (ptTemp != Point.Empty) {
ptRegList.Add(ptTemp);
lstTemp.Add(ptTemp);
this.SetColorFormByColorInfo(ptTemp.X, ptTemp.Y, clrSet);
nCount++;
if (ptTemp.X < rect.Left) { rect.Width = rect.Right - ptTemp.X; rect.X = ptTemp.X; }
if (ptTemp.Y < rect.Top) { rect.Height = rect.Bottom - ptTemp.Y; rect.Y = ptTemp.Y; }
if (ptTemp.X > rect.Right) rect.Width = ptTemp.X - rect.Left;
if (ptTemp.Y > rect.Bottom) rect.Height = ptTemp.Y - rect.Top;
} else
ptRegList.RemoveAt(ptRegList.Count - 1);
}
rect.Width += 1; rect.Height += 1;
if (nCount < nPixelMin || nCount > nPixelMax) {
foreach (var v in lstTemp) {
this.SetColorFormByColorInfo(v.X, v.Y, Color.White);
}
return Rectangle.Empty;
}
return rect;
}

private Point GetNextPoint(Point ptStart, int nArgb) {
if (m_bmpData.Height > ptStart.Y + 1 && this.GetArgbFormByColor(ptStart.X, ptStart.Y + 1) == nArgb)
return new Point(ptStart.X, ptStart.Y + 1);
if (m_bmpData.Width > ptStart.X + 1 && this.GetArgbFormByColor(ptStart.X + 1, ptStart.Y) == nArgb)
return new Point(ptStart.X + 1, ptStart.Y);
if (0 <= ptStart.Y - 1 && this.GetArgbFormByColor(ptStart.X, ptStart.Y - 1) == nArgb)
return new Point(ptStart.X, ptStart.Y - 1);
if (0 <= ptStart.X - 1 && this.GetArgbFormByColor(ptStart.X - 1, ptStart.Y) == nArgb)
return new Point(ptStart.X - 1, ptStart.Y);
if (0 <= ptStart.X - 1 && m_bmpData.Height > ptStart.Y + 1 && this.GetArgbFormByColor(ptStart.X - 1, ptStart.Y + 1) == nArgb)
return new Point(ptStart.X - 1, ptStart.Y + 1);
if (m_bmpData.Width > ptStart.X + 1 && m_bmpData.Height > ptStart.Y + 1 && this.GetArgbFormByColor(ptStart.X + 1, ptStart.Y + 1) == nArgb)
return new Point(ptStart.X + 1, ptStart.Y + 1);
if (m_bmpData.Width > ptStart.X + 1 && 0 <= ptStart.Y - 1 && this.GetArgbFormByColor(ptStart.X + 1, ptStart.Y - 1) == nArgb)
return new Point(ptStart.X + 1, ptStart.Y - 1);
if (0 <= ptStart.X - 1 && 0 <= ptStart.Y - 1 && this.GetArgbFormByColor(ptStart.X - 1, ptStart.Y - 1) == nArgb)
return new Point(ptStart.X - 1, ptStart.Y - 1);
return Point.Empty;
}

private int GetArgbFormByColor(int x, int y) {
return Color.FromArgb(255,
m_byColorInfo[y * m_bmpData.Stride + x * 3],
m_byColorInfo[y * m_bmpData.Stride + x * 3 + 1],
m_byColorInfo[y * m_bmpData.Stride + x * 3 + 2]).ToArgb();
}

private void SetColorFormByColorInfo(int x, int y, Color clr) {
m_byColorInfo[y * m_bmpData.Stride + x * 3] = clr.B;
m_byColorInfo[y * m_bmpData.Stride + x * 3 + 1] = clr.G;
m_byColorInfo[y * m_bmpData.Stride + x * 3 + 2] = clr.R;
}
  • 打赏
  • 举报
回复
有时想起 2016-08-29
求解答呀。。。。。。。。。。。。。。。。。。。。。
  • 打赏
  • 举报
回复
crystal_lz 2016-08-29
你是要白色的个数? 而且你的图都张差不多这个样子 ?
  • 打赏
  • 举报
回复
有时想起 2016-08-26
呀 在线等啊
  • 打赏
  • 举报
回复
相关推荐
发帖
C#
加入

10.6w+

社区成员

.NET技术 C#
申请成为版主
帖子事件
创建了帖子
2016-08-25 04:55
社区公告

让您成为最强悍的C#开发者