《图像处理实例》 之 寻找山脊线
寻找山脊线算法
以下的改进是http://www.imagepy.org/的作者原创,我只是对其理解之后改进和说明,欢迎大家使用这个小软件!
C++版本已经编写完毕,有需要的朋友请留邮箱
算法含义:
提取一个山脉的山峰,图像中就是在距离变换之后提取局部最亮的线
算法应用:
用作图像的断裂修补
方法:
1.直接用分水岭算法进行区域分割。
2.类似分水岭的算法,找山脊线。
分水岭算法:
这里有个哲学的思想,还是开头大佬点拨我的,修补前景就等价于分割背景,一定要理解这句话的含义,我们把白色的直线当做前景修复对象,那么就等价于用白线去分割黑色的背景。
opencv的分水岭算法不是很好,必须找到合适的mask才能达到要求。
skimage的分水岭相对较好,效果差强人意吧.
分水岭结果如上图,在这基础上阈值一下就可以得到我们的图像(这个图像有多余的线条),然后再和原始图像做差值得到修补的线条,把修补的很长线条去除之后再加上原图就可以了。
大家也发现了一个问题,手动的元素比较多,预处理做的不好(局部极大值找的不好,我用的自适应阈值,效果不好就不上图了),上图的效果算比较好的,至少可以解决我们的问题。
代码:
1 #include<opencv2/opencv.hpp> 2 #include<iostream> 3 using namespace std; 4 using namespace cv; 5 6 #define WINDOW_NAME "【程序窗口1】" 7 Mat g_maskImage, g_srcImage; 8 Point prevPt(-1, -1); 9 static void on_Mouse(int event, int x, int y, int flags, void*); 10 11 int main() 12 { 13 //载入原图,初始化掩膜和灰度图 14 g_srcImage = imread("123.png"); 15 imshow(WINDOW_NAME, g_srcImage); 16 Mat srcImage, grayImage; 17 g_srcImage.copyTo(srcImage); 18 cvtColor(g_srcImage, g_maskImage, COLOR_BGR2GRAY); 19 cvtColor(g_maskImage, grayImage, COLOR_GRAY2BGR); 20 g_maskImage = Scalar::all(0); 21 //设置鼠标回调函数 22 setMouseCallback(WINDOW_NAME, on_Mouse); 23 //轮询按键 24 while (1) 25 { 26 int c = waitKey(0); 27 if ((char)c == 27) break; 28 if ((char)c == '2') { //按键‘2’, 恢复源图 29 g_maskImage = Scalar::all(0); 30 srcImage.copyTo(g_srcImage); 31 imshow("image", g_srcImage); 32 } 33 if ((char)c == '1' || (char)c == ' ') { 34 //定义一些参数 35 vector<vector<Point> > contours; 36 vector<Vec4i> hierarchy; 37 //寻找轮廓 38 findContours(g_maskImage, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE); 39 //轮廓为空时的处理 40 if (contours.empty()) continue; 41 //复制掩膜 42 Mat maskImage(g_maskImage.size(), CV_32S); 43 maskImage = Scalar::all(0); 44 //循环绘制出轮廓 45 int compCount = 0; 46 for (int index = 0; index >= 0; index = hierarchy[index][0], compCount++) 47 drawContours(maskImage, contours, index, Scalar::all(compCount + 1), -1, LINE_8, hierarchy); 48 //compCount为零时的处理 49 if (compCount == 0) 50 continue; 51 //生成随机颜色 52 vector<Vec3b> colorTab; 53 for (unsigned int i = 0; i < compCount; i++) { 54 int b = theRNG().uniform(0, 255); 55 int g = theRNG().uniform(0, 255); 56 int r = theRNG().uniform(0, 255); 57 colorTab.push_back(Vec3b((uchar)b, (uchar)g, (uchar)r)); 58 } 59 //计算处理时间并输出到窗口中 60 double dTime = (double)getTickCount(); 61 watershed(srcImage, maskImage); 62 dTime = (double)getTickCount() - dTime; 63 printf("处理时间=%gms\n", dTime*1000. / getTickFrequency()); 64 //双层循环,将分水岭图像遍历存入watershedImage中 65 Mat watershedImage(maskImage.size(), CV_8UC3); 66 for (unsigned int i = 0; i < maskImage.rows; i++) 67 for (unsigned int j = 0; j < maskImage.cols; j++) 68 { 69 int index = maskImage.at<int>(i, j); 70 if (index == -1) 71 watershedImage.at<Vec3b>(i, j) = Vec3b(255, 255, 255); 72 else if (index <= 0 || index > compCount) 73 watershedImage.at<Vec3b>(i, j) = Vec3b(0, 0, 0); 74 else 75 watershedImage.at<Vec3b>(i, j) = colorTab[index - 1]; 76 } 77 //混合灰度图和分水岭效果图并显示最终的窗口 78 //watershedImage = watershedImage*0.5 + grayImage*0.5; 79 imshow("watershed transform", watershedImage); 80 } 81 } 82 return 0; 83 } 84 85 static void on_Mouse(int event, int x, int y, int flags, void*) 86 { 87 //处理鼠标不在窗口中的情况 88 if (x < 0 || x >= g_srcImage.cols || y < 0 || y >= g_srcImage.rows) return; 89 //处理鼠标左键相关消息 90 if (event == EVENT_LBUTTONUP || !(flags & EVENT_FLAG_LBUTTON)) //左键抬起动作或处于没有按下状态 91 prevPt = Point(-1, -1); 92 else if (event == EVENT_LBUTTONDOWN) //左键按下动作 93 prevPt = Point(x, y); 94 //鼠标左键按下并移动,绘制出白色线条 95 else if (event == EVENT_MOUSEMOVE && (flags & EVENT_FLAG_LBUTTON)) 96 { 97 Point pt(x, y); 98 if (prevPt.x < 0) prevPt = pt; 99 line(g_maskImage, prevPt, pt, Scalar::all(255), 5); 100 line(g_srcImage, prevPt, pt, Scalar::all(255), 5); 101 prevPt = pt; 102 imshow(WINDOW_NAME, g_srcImage); 103 } 104 105 }
找山脊线算法:
类似于骨架提取、图像细化、中轴线提取等思想
把白色的线当做前景图,然后进行距离变换,之后进行全局阈值把前景全部包括在mask里面,接着利用原始图对mask进行操作,具体的细节看代码分析。
以下是效果图,很完美的解决了问题。
算法的原理:
第一步:对图像进行距离变换---->>>之后阈值化(全局阈值就好)
例如:效果图
注释:这里不进行距离变换,直接进行阈值化也可以,但是对于特殊的图像效果很差。因为掩膜的应用可以结合分水岭[0:255]进行操作,没有距离变换的掩膜就只有255,这就和图像细化或者中轴线算法差不多了。
原图
距离变换图
掩膜图
结果图
掩膜图
结果图
第二步:对二值化图像进行标记(做mask)
边界标记成4,这里为了防止越界,按照opencv c++的说法就是img.rows-1....
背景标记成2
前景标记成0,这里是除去图形边界的前景
图形边界标记成1
第三步:分水岭算法
进行操作的是距离图+掩膜图(dis+mask)
这里使用涨水的方式对像素进行操作,从刚开始标记的边界1开始向内部涨水,由于距离变换之后映射到【0-255】,所以水从0开始涨,知道255为止:
这一步关键一点是内部的凹池,采用类似水漫算法进行:
就这样把低于水平线的像素都填充为背景2了,当然按照其他的行列循环也是可以的,怎么写都行!
注释:
这里有几个小技巧:
1.因为是从边界开始判断的,比如边界高度为100,那么水就从100开始涨,不然0-99是没意义的,具体代码见程序说217行。
2.每一次的循环最少是图形一圈,因为这里以涨水为标准,比如上面的以原图二值化为掩膜,那么图像都为255,这时候就是一次性得出山脊线。
简单的说就是每次处理的单位都是一个水平线,比如水平线是200,那么边界高度为201就是下一次涨水再进行处理。
3.掩膜取得合适得出的图像效果最好,也不是越大越好,具体例子就不举了。
4.因为这里查表遵循的是不断裂原则(貌似图像细化和骨架提取都是这样),回头想想你把掩膜图进行细化然后再和原图叠加也能进行图像修复哈!
下面是我自己的一个误区:(这里大家看完上面说明就知道以下的问题是不存在的)
当然这里的算法不稳定,一些特殊的图像还是不行,比如下面的图像,水还没涨到200,图就已经分割完了,程序是水涨一次就分割一次,但是这个图明显都大于200.
1 from scipy.misc import imread 2 import matplotlib.pyplot as plt 3 import numpy as np 4 from numba import jit 5 from skimage.data import camera 6 import scipy.ndimage as ndimg 7 from time import time 8 import cv2 9 from scipy.ndimage import label, generate_binary_structure 10 11 strc = np.ones((3, 3), dtype=np.bool) 12 13 14 def count(n): 15 a = [(n>>i) & 1 for i in range(8)] 16 if sum(a)<=1:return False 17 if a[1] & a[3] & a[5] & a[7]:return False 18 a = np.array([[a[0],a[1],a[2]], 19 [a[7], 0 ,a[3]], 20 [a[6],a[5],a[4]]]) 21 n = label(a, strc)[1] 22 return n<2 23 24 25 lut = np.array([count(n) for n in range(256)]) 26 lut = np.dot(lut.reshape((-1, 8)), [1, 2, 4, 8, 16, 32, 64, 128]).astype(np.uint8) 27 28 29 #@jit 30 def core(n): 31 a = np.zeros(8, dtype=np.uint8) 32 for i in range(8): 33 a[i] = (n >> i * 2) & 3 34 if a[1] == 1 and a[0] == 0: a[0] = 1 35 if a[1] == 1 and a[2] == 0: a[0] = 1 36 if a[3] == 1 and a[2] == 0: a[2] = 1 37 if a[3] == 1 and a[4] == 0: a[4] = 1 38 if a[5] == 1 and a[4] == 0: a[4] = 1 39 if a[5] == 1 and a[6] == 0: a[6] = 1 40 if a[7] == 1 and a[6] == 0: a[6] = 1 41 if a[7] == 1 and a[0] == 0: a[0] = 1 42 for i in range(8): 43 if a[i] == 0 or a[i] == 2: a[i] = 0 44 if a[i] == 1 or a[i] == 3: a[i] = 1 45 return np.dot(a, [1, 2, 4, 8, 16, 32, 64, 128]) 46 47 48 index = np.array([core(i) for i in range(65536)], dtype=np.uint8) 49 50 # 51 ''' 52 lut = np.array([223, 221, 1, 221, 1, 221, 1, 221, 1, 0, 0, 0, 1, 221, 1, 221, 207, 204, 53 0, 204, 207, 51, 207, 1, 207, 204, 0, 204, 207, 51, 207, 51], dtype=np.uint8) 54 ''' 55 56 # 57 def nbs8(h, w): 58 return np.array([-w - 1, -w, -w + 1, +1, +w + 1, +w, +w - 1, -1], dtype=np.int32) 59 60 #类似创建2X2内核(上下左右4个数) 61 def nbs4(h, w): 62 return np.array([-1, -w, 1, w], dtype=np.int32) 63 64 65 #@jit 66 67 def fill(img, msk, p, level, pts, s, nbs, buf): 68 n = 0 69 cur = 0 70 buf[0] = p 71 msk[p] = 2 72 bs = 1 73 while cur < bs: 74 p = buf[cur] 75 for dp in nbs: 76 if msk[p + dp] != 0: continue 77 if img[p + dp] < level: 78 buf[bs] = p + dp 79 msk[p + dp] = 2 80 bs += 1 81 if bs == len(buf): 82 buf[:bs - cur] = buf[cur:bs] 83 bs -= cur 84 cur = 0 85 else: 86 pts[s + n] = p + dp 87 msk[ p + dp] = 1 88 n += 1 89 cur += 1 90 return n 91 92 93 #@jit 94 def check(msk, p, nbs, lut): 95 c = 0 96 s = 0 97 for i in range(8): 98 v = msk[p + nbs[i]] 99 # if v==0: c|=(0<<i*2) 100 if v == 1: c |= (1 << i * 2) 101 if v == 2: c |= (2 << i * 2) 102 if v == 3: c |= (3 << i * 2) 103 v = index[c] 104 if lut[v // 8] >> v % 8 & 1: 105 msk[p] = 2 106 else: 107 msk[p] = 3 108 109 110 #@jit 111 def step(img, msk, pts, s, level, nbs, nbs8): 112 ddd = 0 113 cur = 0 114 buf = np.zeros(10240, dtype=np.int64) 115 while cur < s: 116 p = pts[cur] 117 if img[p] > level: 118 cur += 1 119 continue 120 121 filled = False 122 for dp in nbs: 123 if msk[p + dp] == 4: msk[p] = 2 124 if msk[p + dp] == 0: 125 if img[p + dp] >= level: 126 msk[p + dp] = 1 127 pts[s] = p + dp 128 s += 1 129 else: 130 n = fill(img, msk, p, level, pts, s, nbs, buf) 131 s += n 132 filled = True 133 134 if filled: 135 cur += 1 136 continue 137 elif msk[p] == 1: 138 check(msk, p, nbs8, lut) 139 140 cur += 1 141 return cur 142 143 144 @jit 145 def clear(msk, pts, s): 146 cur = 0 147 for c in range(s): 148 if msk[pts[c]] == 1: 149 pts[cur] = pts[c] 150 cur += 1 151 return cur 152 153 154 @jit 155 def collect(img, mark, nbs, pts): 156 bins = np.zeros(img.max() + 1, dtype=np.uint32) 157 cur = 0 158 ''' 159 for p in range(len(mark)): 160 if mark[p] != 0: continue 161 for dp in nbs: 162 if mark[p + dp] == 1: 163 mark[p] = 2 164 ''' 165 for p in range(len(mark)): 166 if mark[p] == 1: mark[p] = 2 167 for p in range(len(mark)): 168 if mark[p] != 0: continue 169 s = 0 170 for dp in nbs: 171 if mark[p + dp] == 2: 172 s += 1 173 mark[p] = 1 174 pts[cur] = p 175 cur += 1 176 break 177 if s == 0: bins[img[p]] += 1 178 return cur, bins 179 180 181 #@jit 182 def watershed(img, mark): 183 oimg, omark = img, mark 184 ndim = img.ndim 185 mark[[0, -1], :] = 4 186 mark[:, [0, -1]] = 4 187 188 nb4 = nbs4(*img.shape) 189 nb8 = nbs8(*img.shape) 190 acc = np.cumprod((1,) + img.shape[::-1][:-1])[::-1] 191 img = img.ravel() 192 mark = mark.ravel() 193 194 pts = np.zeros(131072, dtype=np.int64) 195 s, bins = collect(img, mark, nb4, pts) 196 for level in range(len(bins)): 197 if bins[level] == 0: continue 198 s = clear(mark, pts, s) 199 s = step(img, mark, pts, s, level, nb4, nb8) 200 ''' 201 dem = cv2.imread('gis1.jpg',0) 202 plt.imshow(dem, cmap='gray') 203 mark = (dem > 150).astype(np.uint8) 204 plt.imshow(mark, cmap='gray') 205 plt.show() 206 207 watershed(dem, mark.copy()) 208 start = time() 209 watershed(dem, mark) 210 print(time() - start) 211 dem[:] = dem * 0.8 212 dem[mark == 3] = 255 213 plt.imshow(dem, cmap='gray') 214 plt.show() 215 ''' 216 #dem = imread('line2.png') 217 dem = cv2.imread('0.jpg') 218 dem = cv2.cvtColor(dem,cv2.COLOR_BGR2GRAY) 219 ret2, dem = cv2.threshold(dem, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU) 220 dis = ndimg.distance_transform_edt(~dem).astype(np.uint8) 221 dis = ~dis 222 mark = (dis<230).astype(np.uint8) 223 plt.imshow(dis, cmap='gray') 224 plt.imshow(mark, cmap='gray') 225 watershed(dis, mark) 226 dem //= 2 227 dem[mark==3] = 255 228 plt.imshow(dem, cmap='gray') 229 plt.show()
C++版本:
1 //---table 2 uchar lut[] = { 200, 206, 220, 204, 0, 207, 0, 204, 0, 207, 221, 51, 1, 207, 221, 51, 3 0, 0, 221, 204, 0, 0, 0, 204, 1, 207, 221, 51, 1, 207, 221, 51 }; 4 5 //---FindRidge 6 void FindRidge(InputArray& _src, Mat& mask, vector<Point> Edge_Point, uchar thred) 7 { 8 Mat src = _src.getMat();// , mask = _mask.getMat(); 9 10 mask = src.clone(); 11 bitwise_not(mask, mask); 12 distanceTransform(mask, mask, DIST_L2, DIST_MASK_3, 5); 13 normalize(mask, mask, 0, 255, NORM_MINMAX); 14 mask.convertTo(mask, CV_8UC1); 15 threshold(mask, mask, thred, 255, THRESH_BINARY_INV); 16 Mat temp = mask.clone(); 17 18 bitwise_not(mask, mask); 19 mask = mask - 253; 20 Mat rows = Mat::ones(Size(src.cols, 1), CV_8UC1), cols = Mat::zeros(Size(1, src.rows), CV_8UC1); 21 rows.setTo(4); cols.setTo(4); 22 Mat src_rows_beg = mask.row(0), src_cols_beg = mask.col(0); 23 Mat src_rows_end = mask.row(src.rows - 1), src_cols_end = mask.col(src.cols - 1); 24 rows.copyTo(src_rows_beg); rows.copyTo(src_rows_end); 25 cols.copyTo(src_cols_beg); cols.copyTo(src_cols_end); 26 27 Edge_Point = FindEdge(temp, mask); 28 bool TF = true; 29 while (TF) 30 { 31 TF = false; 32 for (size_t i = 0; i < mask.rows - 1; i++) 33 { 34 uchar* msk_up = mask.ptr(i - 1); 35 uchar* msk = mask.ptr(i); 36 uchar* msk_dw = mask.ptr(i + 1); 37 for (size_t j = 0; j < mask.cols - 1; j++) 38 { 39 uchar _temp_data = msk[j]; 40 msk[j] = msk[j] == 2 && (msk_up[j] == 255 || msk_up[j] == 0) 41 && (msk_dw[j] == 255 || msk_dw[j] == 0) 42 && (msk[j - 1] == 255 || msk[j - 1] == 0) 43 && (msk[j + 1] == 255 || msk[j + 1] == 0) ? 0 : msk[j]; 44 msk[j] = msk[j] == 0 && (msk_up[j] == 2 || msk_dw[j] == 2 || msk[j - 1] == 2 || msk[j + 1] == 2) ? 2 : msk[j]; 45 TF = _temp_data != msk[j] ? true : TF; 46 } 47 } 48 } 49 50 distanceTransform(src, src, DIST_L2, DIST_MASK_3, 5); 51 normalize(src, src, 0, 255, NORM_MINMAX); 52 src.convertTo(src, CV_8UC1); 53 54 const int histSize = 255; 55 float range[] = { 0, 255 }; 56 const float* histRange = { range }; 57 Mat hist; 58 calcHist(&src, 1, 0, Mat(), hist, 1, &histSize, &histRange, true, false); 59 60 hist = hist.reshape(1,1); 61 normalize(hist, hist, 0, 1000, NORM_MINMAX); 62 hist.convertTo(hist, CV_32FC1); 63 //float* ptr = hist.ptr(0); 64 for (size_t level = 0; level <= 255; level++) 65 { 66 if (!hist.at<float>(0,level)) continue; 67 FloorEdge(src, Edge_Point, mask, level); 68 } 69 } 70 71 /* 72 73 vector<Point> FindEdge(InputArray& _src, Mat& mask) 74 { 75 Mat src1 = _src.getMat(),src = src1.clone(); 76 Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3)); 77 morphologyEx(src, src, MORPH_ERODE, kernel); 78 vector<Point> wjy_Point; 79 vector<vector<Point>> contours; 80 vector<Vec4i> hierarchy; 81 findContours(src, contours, hierarchy, RETR_TREE, CHAIN_APPROX_NONE, Point(-1, -1)); 82 for (size_t i = 0; i < contours.size(); i++) 83 { 84 for (size_t j = 0; j < contours[i].size(); j++) 85 { 86 wjy_Point.push_back(contours[i][j]); 87 mask.at<uchar>(contours[i][j]) = 255; 88 } 89 } 90 return wjy_Point; 91 } 92 */ 93 94 95 vector<Point> FindEdge(Mat& src,Mat& mask) 96 { 97 //Mat src = mask.clone(); 98 Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3)); 99 //morphologyEx(src, src, MORPH_ERODE, kernel); 100 vector<Point> wjy_Point; 101 vector<vector<Point>> contours; 102 vector<Vec4i> hierarchy; 103 findContours(src, contours, hierarchy, RETR_TREE, CHAIN_APPROX_NONE, Point(-1, -1)); 104 for (size_t i = 0; i < contours.size(); i++) 105 { 106 for (size_t j = 0; j < contours[i].size(); j++) 107 { 108 wjy_Point.push_back(contours[i][j]); 109 mask.at<uchar>(contours[i][j]) = 255; 110 } 111 } 112 return wjy_Point; 113 } 114 115 116 void FloorEdge(InputArray& _src, vector<Point>& Edge_Point, Mat& mask,int level) 117 { 118 Mat src = _src.getMat(); 119 for (int i = 0; i < Edge_Point.size(); i++) 120 { 121 vector<Point> temp_vector; 122 temp_vector.push_back(Point(Edge_Point[i].x, Edge_Point[i].y - 1)); 123 temp_vector.push_back(Point(Edge_Point[i].x, Edge_Point[i].y + 1)); 124 temp_vector.push_back(Point(Edge_Point[i].x - 1, Edge_Point[i].y)); 125 temp_vector.push_back(Point(Edge_Point[i].x + 1, Edge_Point[i].y)); 126 uchar* msk = mask.ptr(Edge_Point[i].y); 127 uchar* img = src.ptr(Edge_Point[i].y); 128 if (img[Edge_Point[i].x] > level) continue; 129 bool Flag = true; 130 uchar count_num = 0; 131 for (size_t j = 0; j < temp_vector.size(); j++) 132 { 133 uchar* pre_data = mask.ptr(temp_vector[j].y); 134 if (pre_data[temp_vector[j].x] == 2 || pre_data[temp_vector[j].x] == 4) 135 { 136 pre_data[temp_vector[j].x] = 2; 137 continue; 138 } 139 else if (pre_data[temp_vector[j].x] == 128 || pre_data[temp_vector[j].x] == 255) 140 { 141 continue; 142 count_num++; 143 } 144 else 145 { 146 if (src.at<uchar>(temp_vector[j]) >= level) 147 { 148 count_num++; 149 pre_data[temp_vector[j].x] = 255; 150 Edge_Point.push_back(temp_vector[j]); 151 //Edge_Point.insert(Edge_Point.begin()+i+1,temp_vector[j]); 152 } 153 else 154 { 155 int temp = FillBlock(src, Edge_Point, mask, level, Edge_Point[i]); 156 Flag = false; 157 } 158 } 159 } 160 if (false) 161 { 162 msk[Edge_Point[i].x] = 128; 163 Edge_Point.erase(Edge_Point.begin() + i); 164 i--; 165 continue; 166 } 167 else if (count_num == 4) 168 { 169 Edge_Point.push_back(Edge_Point[i]); 170 Edge_Point.erase(Edge_Point.begin() + i); 171 i--; 172 continue; 173 } 174 else if (msk[Edge_Point[i].x] == 255) 175 { 176 msk[Edge_Point[i].x] = CheckData(mask, Edge_Point[i]) == true ? 128 : 2; 177 Edge_Point.erase(Edge_Point.begin() + i); 178 i--; 179 } 180 } 181 } 182 183 int FillBlock(InputArray& _src, vector<Point>& Edge_Point, Mat& mask, int level, Point center) 184 { 185 Mat src = _src.getMat(); 186 mask.at<uchar>(center) = 2; 187 vector<Point> fill_point; 188 int count = 0, count_mount = 1; 189 fill_point.push_back(center); 190 while (count < count_mount) 191 { 192 vector<uchar*> img; 193 vector<uchar*> msk; 194 for (int i = -1; i < 2; i++) 195 { 196 img.push_back(src.ptr<uchar>(fill_point[count].y + i)); 197 msk.push_back(mask.ptr<uchar>(fill_point[count].y + i)); 198 } 199 for (size_t i = 0; i < 3; i++) 200 { 201 for (int j = -1; j < 2; j++) 202 { 203 if (img[i][fill_point[count].x + j] < level && !(j == 0 && i == 1) && msk[i][fill_point[count].x + j] == 0) 204 { 205 fill_point.push_back(Point(fill_point[count].x + j, fill_point[count].y + i - 1)); 206 msk[i][fill_point[count].x + j] = 2; 207 } 208 else if (img[i][fill_point[count].x + j] >= level && msk[i][fill_point[count].x + j] == 0) 209 { 210 Edge_Point.push_back(Point(fill_point[count].x + j, fill_point[count].y + i - 1)); 211 msk[i][fill_point[count].x + j] = 255; 212 } 213 } 214 } 215 //msk[1][fill_point[count].x] = 2; 216 count_mount = fill_point.size() - 1; 217 fill_point.erase(fill_point.begin()); 218 } 219 return 0; 220 } 221 222 223 bool CheckData(Mat& mask, Point center) 224 { 225 uchar* msk_up = mask.ptr(center.y - 1); 226 uchar* msk = mask.ptr(center.y); 227 uchar* msk_dw = mask.ptr(center.y + 1); 228 int num[8]; 229 int sum = (num[0] = msk_up[center.x - 1] == 255 || msk_up[center.x - 1] == 128 || msk_up[center.x - 1] == 0 ? 1 : 0) 230 + (num[1] = msk_up[center.x] == 255 || msk_up[center.x] == 128 || msk_up[center.x] == 0 ? 1 : 0) * 2 231 + (num[2] = msk_up[center.x + 1] == 255 || msk_up[center.x + 1] == 128 || msk_up[center.x + 1] == 0 ? 1 : 0) * 4 232 + (num[3] = msk[center.x - 1] == 255 || msk[center.x - 1] == 128 || msk[center.x - 1] == 0 ? 1 : 0) * 8 233 + (num[4] = msk[center.x + 1] == 255 || msk[center.x + 1] == 128 || msk[center.x + 1] == 0 ? 1 : 0) * 16 234 + (num[5] = msk_dw[center.x - 1] == 255 || msk_dw[center.x - 1] == 128 || msk_dw[center.x - 1] == 0 ? 1 : 0) * 32 235 + (num[6] = msk_dw[center.x] == 255 || msk_dw[center.x] == 128 || msk_dw[center.x] == 0 ? 1 : 0) * 64 236 + (num[7] = msk_dw[center.x + 1] == 255 || msk_dw[center.x + 1] == 128 || msk_dw[center.x + 1] == 0 ? 1 : 0) * 128; 237 return ((lut[uchar(sum / 8)] >> sum % 8) & 1) != 1 ? true : false; 238 }
-------------------------------------------
个性签名:衣带渐宽终不悔,为伊消得人憔悴!
如果觉得这篇文章对你有小小的帮助的话,记得关注再下的公众号,同时在右下角点个“推荐”哦,博主在此感谢!