• 图像轮廓跟踪


         最近闲来无事,做了一个关于图像轮廓提取的事情,觉得提有意思的,所以想拿来与大家分享。全部代码如下:

    图像轮廓提取按钮事件
    1  private void OutLine_Click(object sender, EventArgs e)
    2 {
    3 if (bitMap != null)
    4 {
    5 ImageFeature imgFeature = new ImageFeature(bitMap);
    6 imgFeature.Draw();
    7 Invalidate();
    8 }
    9 }
    图像轮廓提取类
      1  public class ImageFeature
    2 {
    3 public Bitmap bitMap; //图像
    4 private int w, h; //图像宽、高
    5 public int[,] binary; //图像二值化数组
    6 private int[] baseStartPoint = new int[2]; //图像基本起点坐标
    7 private int[] standardStartPoint = new int[2]; //图像标准起点坐标
    8
    9 private int[,] boundArray; //边界点集合
    10 private int count = 0; //边界点个数
    11 private int[] codes; //链码数组
    12
    13 public ImageFeature(Bitmap b)
    14 {
    15 bitMap = b;
    16 w = b.Width;
    17 h = b.Height;
    18 binary = new int[w, h];
    19 }
    20
    21 /// <summary>
    22 /// 图像二值化函数
    23 /// </summary>
    24 public void ToBianry()
    25 {
    26 for (int j = 0; j < h; j++)
    27 for (int i = 0; i < w; i++)
    28 if (bitMap.GetPixel(i, j).B > 128) binary[i, j] = 0;
    29 else binary[i, j] = 1;
    30 }
    31
    32 /// <summary>
    33 /// 图像基本起点的查找
    34 /// 从下而上、从左到右
    35 /// </summary>
    36 private void FindBaseStartPoint()
    37 {
    38 for(int i=0;i<w;i++)
    39 for(int j=h-1;j>=0;j--)
    40 if (binary[i, j] == 1)
    41 {
    42 baseStartPoint[0] = i;
    43 baseStartPoint[1] = j;
    44 j = -1;
    45 i = w;
    46 }
    47 }
    48
    49 /// <summary>
    50 /// 图像轮廓跟踪,以逆时针八个方向为准
    51 /// →、↗、↑、↖、←、↙、↓,↘
    52 /// </summary>
    53 private void OutLine()
    54 {
    55 int[,] director = { {1,0},{1,-1},{0,-1},{-1,-1},{-1,0},{-1,1},{0,1},{1,1}}; //八个方向向量
    56 bool bFindBasePoint = false; //是否已经找到了原启始点
    57 int k=0; //方向向量循环变量
    58 bool bFindNextPoint = false; //是否已经找到下一个点
    59 int X, Y; //点坐标中间变量
    60 boundArray=new int[w*h/8,2]; //对边界点集的设定
    61 int[] codeArray=new int[w*h/8];
    62 boundArray[0,0]=baseStartPoint[0];
    63 boundArray[0,1]=baseStartPoint[1];
    64 while (!bFindBasePoint)
    65 {
    66 bFindNextPoint = false;
    67 while(!bFindNextPoint)
    68 {
    69 X = boundArray[count, 0] + director[k, 0];
    70 Y = boundArray[count, 1] + director[k, 1];
    71 if (X < 0) X = 0;
    72 if (X> w) X = w;
    73 if (Y < 0) Y = 0;
    74 if (Y > h) Y = h;
    75 if (binary[X, Y] == 1)
    76 {
    77 bFindNextPoint = true;
    78 codeArray[count] = k;
    79 count++;
    80 //记录边界点坐标
    81 boundArray[count, 0] = X;
    82 boundArray[count, 1] = Y;
    83 if (X == baseStartPoint[0] && Y == baseStartPoint[1]) bFindBasePoint = true;
    84 k -= 2;
    85 if (k < 0) k += 8;
    86 }
    87 else
    88 {
    89 k++;
    90 if (k == 8) k = 0;
    91 }
    92 }
    93 }
    94
    95 //规范化两码
    96 int max=0,num=0,pointSite=0,tem_i;
    97 for (int i = 0; i < count; i++)
    98 {
    99 if (codeArray[i] == 0)
    100 {
    101 tem_i = i;
    102 num = 1;
    103 while (codeArray[i + 1] == 0)
    104 {
    105 num++;
    106 i++;
    107 }
    108 if (num > max)
    109 {
    110 max = num;
    111 pointSite = tem_i;
    112 }
    113 }
    114 }
    115 codes=new int[count]; //链码数组
    116 for(int i=0;i<count-pointSite;i++) codes[i]=codeArray[i+pointSite];
    117 for(int i=0;i<pointSite;i++) codes[count-pointSite+i]=codeArray[i];
    118 standardStartPoint[0] = boundArray[pointSite, 0];
    119 standardStartPoint[1]=boundArray[pointSite,1];
    120 }
    121
    122 /// <summary>
    123 /// 描绘轮廓坐标
    124 /// </summary>
    125 private void DrawOutLine()
    126 {
    127 for (int j = 0; j < h; j++)
    128 for (int i = 0; i < w; i++) bitMap.SetPixel(i, j, Color.FromArgb(255, 255, 255));
    129 for (int i = 0; i < count; i++) bitMap.SetPixel(boundArray[i, 0], boundArray[i, 1], Color.FromArgb(0, 0, 0));
    130 }
    131
    132 /// <summary>
    133 /// 画轮廓
    134 /// </summary>
    135 public void Draw()
    136 {
    137 ToBianry();
    138 FindBaseStartPoint();
    139 OutLine();
    140 DrawOutLine();
    141 }
    142 }

        图像处理的过程:

        我们要打开的图片是:

    经过轮廓提取操作以后我们可以得到的结果图片是:

         这是通过WinForm来实现的。具体的细节,我在这就不赘述了。我希望能够给大家带来帮助同时也希望大家能够多多的支持和提宝贵建议。

      

      

  • 相关阅读:
    IDEA快捷键
    关于redis key命名规范的设计 【转载】
    Mybatis数据源与连接池 【转载】
    通过缓冲区读文件和非缓冲区读文件有什么区别
    BCB6 使用正则表达式的例子
    QT在子窗口外单击关闭子窗口
    QT5 中文乱码
    QT 鼠标右键菜单
    关于线程池的几个问题
    关于ConcurentHashMap的几个问题
  • 原文地址:https://www.cnblogs.com/sqljiang0916/p/2148864.html
Copyright © 2020-2023  润新知