1 #include <opencv2/opencv.hpp>  
  2 #include <iostream>  
  3 #include <vector>  
  4 #include <limits>  
  5 
  6 using namespace cv;
  7 using namespace std;
  8 
  9 /**
 10 * @brief 对输入图像进行细化
 11 * @param[in] src为输入图像,用cvThreshold函数处理过的8位灰度图像格式,元素中只有0与1,1代表有元素,0代表为空白
 12 * @param[out] dst为对src细化后的输出图像,格式与src格式相同,调用前需要分配空间,元素中只有0与1,1代表有元素,0代表为空白
 13 * @param[in] maxIterations限制迭代次数,如果不进行限制,默认为-1,代表不限制迭代次数,直到获得最终结果
 14 */
 15 void thinImage(IplImage* src, IplImage* dst, int maxIterations = -1)
 16 {
 17     CvSize size = cvGetSize(src);
 18     cvCopy(src, dst);//将src中的内容拷贝到dst中  
 19     int count = 0;  //记录迭代次数  
 20     while (true)
 21     {
 22         count++;
 23         if (maxIterations != -1 && count > maxIterations) //限制次数并且迭代次数到达  
 24             break;
 25         //std::cout << count << ' ';输出迭代次数  
 26         vector<pair<int, int> > mFlag; //用于标记需要删除的点  
 27                                        //对点标记  
 28         for (int i = 0; i<size.height; ++i)
 29         {
 30             for (int j = 0; j<size.width; ++j)
 31             {
 32                 //如果满足四个条件,进行标记  
 33                 //  p9 p2 p3  
 34                 //  p8 p1 p4  
 35                 //  p7 p6 p5  
 36                 int p1 = CV_IMAGE_ELEM(dst, uchar, i, j);
 37                 int p2 = (i == 0) ? 0 : CV_IMAGE_ELEM(dst, uchar, i - 1, j);
 38                 int p3 = (i == 0 || j == size.width - 1) ? 0 : CV_IMAGE_ELEM(dst, uchar, i - 1, j + 1);
 39                 int p4 = (j == size.width - 1) ? 0 : CV_IMAGE_ELEM(dst, uchar, i, j + 1);
 40                 int p5 = (i == size.height - 1 || j == size.width - 1) ? 0 : CV_IMAGE_ELEM(dst, uchar, i + 1, j + 1);
 41                 int p6 = (i == size.height - 1) ? 0 : CV_IMAGE_ELEM(dst, uchar, i + 1, j);
 42                 int p7 = (i == size.height - 1 || j == 0) ? 0 : CV_IMAGE_ELEM(dst, uchar, i + 1, j - 1);
 43                 int p8 = (j == 0) ? 0 : CV_IMAGE_ELEM(dst, uchar, i, j - 1);
 44                 int p9 = (i == 0 || j == 0) ? 0 : CV_IMAGE_ELEM(dst, uchar, i - 1, j - 1);
 45 
 46                 if ((p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9) >= 2 && (p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9) <= 6)
 47                 {
 48                     int ap = 0;
 49                     if (p2 == 0 && p3 == 1) ++ap;
 50                     if (p3 == 0 && p4 == 1) ++ap;
 51                     if (p4 == 0 && p5 == 1) ++ap;
 52                     if (p5 == 0 && p6 == 1) ++ap;
 53                     if (p6 == 0 && p7 == 1) ++ap;
 54                     if (p7 == 0 && p8 == 1) ++ap;
 55                     if (p8 == 0 && p9 == 1) ++ap;
 56                     if (p9 == 0 && p2 == 1) ++ap;
 57 
 58                     if (ap == 1)
 59                     {
 60                         if (p2*p4*p6 == 0)
 61                         {
 62                             if (p4*p6*p8 == 0)
 63                             {
 64                                 //标记  
 65                                 mFlag.push_back(make_pair(i, j));
 66                             }
 67                         }
 68                     }
 69                 }
 70             }
 71         }
 72 
 73         //将标记的点删除  
 74         for (vector<pair<int, int> >::iterator i = mFlag.begin(); i != mFlag.end(); ++i)
 75         {
 76             CV_IMAGE_ELEM(dst, uchar, i->first, i->second) = 0;
 77         }
 78 
 79         //直到没有点满足,算法结束  
 80         if (mFlag.size() == 0)
 81         {
 82             break;
 83         }
 84         else
 85         {
 86             mFlag.clear();//将mFlag清空  
 87         }
 88 
 89         //对点标记  
 90         for (int i = 0; i<size.height; ++i)
 91         {
 92             for (int j = 0; j<size.width; ++j)
 93             {
 94                 //如果满足四个条件,进行标记  
 95                 //  p9 p2 p3  
 96                 //  p8 p1 p4  
 97                 //  p7 p6 p5  
 98                 int p1 = CV_IMAGE_ELEM(dst, uchar, i, j);
 99                 if (p1 != 1) continue;
100                 int p2 = (i == 0) ? 0 : CV_IMAGE_ELEM(dst, uchar, i - 1, j);
101                 int p3 = (i == 0 || j == size.width - 1) ? 0 : CV_IMAGE_ELEM(dst, uchar, i - 1, j + 1);
102                 int p4 = (j == size.width - 1) ? 0 : CV_IMAGE_ELEM(dst, uchar, i, j + 1);
103                 int p5 = (i == size.height - 1 || j == size.width - 1) ? 0 : CV_IMAGE_ELEM(dst, uchar, i + 1, j + 1);
104                 int p6 = (i == size.height - 1) ? 0 : CV_IMAGE_ELEM(dst, uchar, i + 1, j);
105                 int p7 = (i == size.height - 1 || j == 0) ? 0 : CV_IMAGE_ELEM(dst, uchar, i + 1, j - 1);
106                 int p8 = (j == 0) ? 0 : CV_IMAGE_ELEM(dst, uchar, i, j - 1);
107                 int p9 = (i == 0 || j == 0) ? 0 : CV_IMAGE_ELEM(dst, uchar, i - 1, j - 1);
108 
109                 if ((p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9) >= 2 && (p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9) <= 6)
110                 {
111                     int ap = 0;
112                     if (p2 == 0 && p3 == 1) ++ap;
113                     if (p3 == 0 && p4 == 1) ++ap;
114                     if (p4 == 0 && p5 == 1) ++ap;
115                     if (p5 == 0 && p6 == 1) ++ap;
116                     if (p6 == 0 && p7 == 1) ++ap;
117                     if (p7 == 0 && p8 == 1) ++ap;
118                     if (p8 == 0 && p9 == 1) ++ap;
119                     if (p9 == 0 && p2 == 1) ++ap;
120 
121                     if (ap == 1)
122                     {
123                         if (p2*p4*p8 == 0)
124                         {
125                             if (p2*p6*p8 == 0)
126                             {
127                                 //标记  
128                                 mFlag.push_back(make_pair(i, j));
129                             }
130                         }
131                     }
132                 }
133             }
134         }
135         //删除  
136         for (vector<pair<int, int> >::iterator i = mFlag.begin(); i != mFlag.end(); ++i)
137         {
138             CV_IMAGE_ELEM(dst, uchar, i->first, i->second) = 0;
139         }
140 
141         //直到没有点满足,算法结束  
142         if (mFlag.size() == 0)
143         {
144             break;
145         }
146         else
147         {
148             mFlag.clear();//将mFlag清空  
149         }
150     }
151 }
152 
153 int main(int argc, char*argv[])
154 {
155     //获取图像  
156     if (argc != 2)
157     {
158         cout << "参数个数错误!" << endl;
159         return -1;
160     }
161     IplImage *pSrc = cvLoadImage(argv[1], CV_LOAD_IMAGE_GRAYSCALE);
162     if (!pSrc)
163     {
164         cout << "读取文件失败!" << endl;
165         return -1;
166     }
167     IplImage *pTemp = cvCreateImage(cvGetSize(pSrc), pSrc->depth, pSrc->nChannels);
168     IplImage *pDst = cvCreateImage(cvGetSize(pSrc), pSrc->depth, pSrc->nChannels);
169 
170     //将原图像转换为二值图像  
171     cvThreshold(pSrc, pTemp, 128, 1, CV_THRESH_BINARY);
172     //图像细化  
173     thinImage(pTemp, pDst);
174 
175     for (int i = 0; i<pDst->height; ++i)
176     {
177         for (int j = 0; j<pDst->width; ++j)
178         {
179             if (CV_IMAGE_ELEM(pDst, uchar, i, j) == 1)
180                 CV_IMAGE_ELEM(pDst, uchar, i, j) = 255;
181         }
182     }
183 
184     namedWindow("src", CV_WINDOW_AUTOSIZE);
185     namedWindow("dst", CV_WINDOW_AUTOSIZE);
186     cvShowImage("src", pSrc);
187     cvShowImage("dst", pDst);
188 
189     waitKey(0);
190 }