精华内容
下载资源
问答
  • 轮廓提取试验

    千次阅读 热门讨论 2018-02-08 10:50:22
    我就是想要类似:https://www.pyimagesearch.com/2015/11/02/watershed-opencv/  这个的效果,将重叠的轮廓分割开成单独的轮廓。 复杂粘连轮廓的处理,要将粘连的轮廓分开,公司的大神用的是轮廓的缺陷点检测,...

    我就是想要类似:https://www.pyimagesearch.com/2015/11/02/watershed-opencv/  这个的效果,将重叠的轮廓分割开成单独的轮廓。

    复杂粘连轮廓的处理,要将粘连的轮廓分开,公司的大神用的是轮廓的缺陷点检测,但他的这个算法我看了下,有的凹点会检测不到,所以有的粘连的地方仍然分不开:

    像这里有6块石头粘连在一起,有的凹陷点就检测不出来。。。

    我看了下谷歌上有人用的:

    这个我想试试。

     

    import numpy as np
    import matplotlib.pyplot as plt
    from scipy import ndimage as ndi
    from skimage import morphology,feature
    
    #创建两个带有重叠圆的图像
    x, y = np.indices((80, 80))
    x1, y1, x2, y2 = 28, 28, 44, 52
    r1, r2 = 16, 20
    mask_circle1 = (x - x1)**2 + (y - y1)**2 < r1**2
    mask_circle2 = (x - x2)**2 + (y - y2)**2 < r2**2
    image = np.logical_or(mask_circle1, mask_circle2)
    
    #现在我们用分水岭算法分离两个圆
    distance = ndi.distance_transform_edt(image) #距离变换
    local_maxi =feature.peak_local_max(distance, indices=False, footprint=np.ones((3, 3)),
                                labels=image)   #寻找峰值
    
    markers = ndi.label(local_maxi)[0] #初始标记点
    labels =morphology.watershed(-distance, markers, mask=image) #基于距离变换的分水岭算法
    
    fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(8, 8))
    axes = axes.ravel()
    ax0, ax1, ax2, ax3 = axes
    
    ax0.imshow(image, cmap=plt.cm.gray, interpolation='nearest')
    ax0.set_title("Original")
    #ax1.imshow(-distance, cmap=plt.cm.jet, interpolation='nearest')
    #ax1.set_title("Distance")
    ax1.imshow(distance, cmap=plt.cm.gray, interpolation='nearest')
    ax1.set_title("Distance")
    ax2.imshow(markers, cmap=plt.cm.spectral, interpolation='nearest')
    ax2.set_title("Markers")
    ax3.imshow(labels, cmap=plt.cm.spectral, interpolation='nearest')
    ax3.set_title("Segmented")
    
    for ax in axes:
        ax.axis('off')
    
    fig.tight_layout()
    plt.show()

    但我看了下:distance_transform_edt()这个函数的意思:

     

     

     Notes
        -----
        The euclidean distance transform gives values of the euclidean
        distance::
    
                        n
          y_i = sqrt(sum (x[i]-b[i])**2)
                        i
    
        where b[i] is the background point (value 0) with the smallest
        Euclidean distance to input points x[i], and n is the
        number of dimensions.
    
        Examples
        --------
        >>> from scipy import ndimage
        >>> a = np.array(([0,1,1,1,1],
        ...               [0,0,1,1,1],
        ...               [0,1,1,1,1],
        ...               [0,1,1,1,0],
        ...               [0,1,1,0,0]))
        >>> ndimage.distance_transform_edt(a)
        array([[ 0.    ,  1.    ,  1.4142,  2.2361,  3.    ],
               [ 0.    ,  0.    ,  1.    ,  2.    ,  2.    ],
               [ 0.    ,  1.    ,  1.4142,  1.4142,  1.    ],
               [ 0.    ,  1.    ,  1.4142,  1.    ,  0.    ],
               [ 0.    ,  1.    ,  1.    ,  0.    ,  0.    ]])

    直接可以用OpenCV中的distanceTransform()代替,效果一致。

     

    这个粘连的,下图就是距离变换与python的第二幅图一致。
    但寻找局部峰值的那个函数:feature.peak_local_max()就有点难办了。。。我试过用minMaxLoc找到全局最大max,然后按0.9*max找到几个极大值!但这是不对的,理论上就不对,高中三角函数学过极大值可能比最大值的0.9倍甚至0.5倍都小,它们之间没有什么关系的。。。所以不行。

    我用了另一种方法:

     

    void localMaxima(Mat src,const int maxZeroSize,const double minPeakValue,vector<Point> &maxLocpts)
    {
        double minVal=0,maxVal=0,diff=0;
        Point minLocPt,maxLocPt;
    
        minMaxLoc(src,&minVal,&maxVal,&minLocPt,&maxLocPt);//计算最大值
    
        while(maxVal>minPeakValue)
    	{
        	maxLocpts.push_back(maxLocPt);
    		Mat rect_part = src(Rect(maxLocPt.x-maxZeroSize,maxLocPt.y-maxZeroSize,2*maxZeroSize,2*maxZeroSize));
    		rect_part.setTo(Scalar(0));
    		//imwrite("temp_peak.jpg",src);
    		minMaxLoc(src,&minVal,&maxVal,&minLocPt,&maxLocPt);//计算极大值
    	}
    }

    然后:

     

     

    int main()
    {
    	char src_folder[100];
    	char dst_folder[100];
    	const size_t img_rows=1456;
    	const size_t img_cols=1936;
    	int threshold_value=150;
    	int element_size=3;//morph element size
    	int blurwidth=3; //blur window size
    	const int area_min=90; //area<area_min,delete it.
    	int area_limitable=5800; //area<area_limitable,need judge
    	const int area_max=15000;
    	int rect_radius_contour=50; //around the contour :neighbors
    	Mat element=getStructuringElement(MORPH_RECT,Size(2*element_size+1,2*element_size+1),
    					Point(element_size,element_size));
    
    	Mat morph_img(img_rows,img_cols,CV_8UC1);
    
    	morph_img=imread("/home/jumper/Ore_projects/ore_granule/tempBinary.jpg",0);
    	threshold(morph_img,morph_img,1,128,CV_THRESH_BINARY);
    	Mat distance_img(img_rows,img_cols,CV_32FC1);
    	distanceTransform(morph_img,distance_img,CV_DIST_L2,3);
    	//imwrite("distance.jpg",distance_img);
    
    
    	vector<Point> peakpts;
    	localMaxima(distance_img,70,80,peakpts);
    //	Mat peakimgs(img_rows,img_cols,CV_8UC1,Scalar(0));
    //	cout<<"peak num: "<<peakpts.size()<<endl;
    //	for(int index=0;index<=peakpts.size();index++)
    //	{
    //		circle(peakimgs,peakpts[index],5,CV_RGB(255,255,255),2);
    //	}
    //	imwrite("peakimg2.jpg",peakimgs);
    
    
    	//marker...
    	Mat marker(img_rows,img_cols,CV_32SC1,Scalar(0));
    	for(int index=0;index!=peakpts.size();index++)
    	{
    		int row=peakpts[index].y;
    		int col=peakpts[index].x;
    		Mat rect_part = marker(Rect(col-70,row-70,2*70,2*70));
    		rect_part.setTo(short(index+1));
    		//marker.ptr<short>(row)[col]=index+1;
    	}
    //	imwrite("marker.jpg",marker);
    
    	Mat src_img(img_rows,img_cols,CV_8UC3);
    	src_img=imread("/home/jumper/Ore_projects/ore_granule/22db_1.bmp");
    	Mat water_src(img_rows,img_cols,CV_8UC3);
    	src_img.copyTo(water_src,morph_img);
    //	imwrite("water_src.jpg",water_src);
    	watershed(water_src,marker);
    
    	Mat contrast_img(img_rows,img_cols,CV_8UC1,Scalar(0));
    	for(int r=0;r!=marker.rows;r++)
    	{
    		for(int c=0;c!=marker.cols;c++)
    		{
    			if(marker.ptr<short>(r)[c]==-1)
    			{
    				circle(contrast_img,Point(c,r),5,CV_RGB(255,255,255),2);
    			}
    		}
    	}
    	imwrite("contrast_img.jpg",contrast_img);
    	//marker.convertTo(marker,CV_8UC1);
    	//imwrite("watershed.jpg",marker);
    
    	return 0;
    }

    我的确得到了那两个极大值点:

     


    我怕就2个点作为初始标记点太寒酸,我还特意将这两个点附近一块地方标记为1和2:显示画出来就是这样!

    然后就可以运行分水岭分割了:这是原图部分:


    but I got nothing!!!

    没有正确分割 没有得到我想要的!!!????

    后来我又用了传说中的grabCut()算法,通过给它赋予可能的前景以及确定的前景和确定的背景,让它找到真正的前景,,,然而。。。不过可能是我操作的问题咯。

    最后我用了另一种方法,既然我找到了盆地的聚水点(不知道是不是这个名词),那我找这个聚水点距离整个轮廓最近的两条边作为它的rect:

    这还是不完善的版本,因为图像的长宽限制没加进去。。。在几处地方都还没做限制,因为我还只是试试效果而已。。。

     

    #include<opencv2/opencv.hpp>
    #include<opencv2/imgproc/imgproc.hpp>
    #include<opencv2/highgui/highgui.hpp>
    #include<iostream>
    #include<fstream>
    #include <vector>
    using namespace cv;
    using namespace std;
    
    void localMaxima(Mat src,const int maxZeroSize,const double minPeakValue,vector<Point> &maxLocpts);
    
    int main()
    {
    	char src_folder[100];
    	char dst_folder[100];
    	const size_t img_rows=1456;
    	const size_t img_cols=1936;
    	int blurwidth=3;
    
    	Mat background_img(img_rows,img_cols,CV_8UC3);
    	background_img=imread("/home/jumper/Ore_projects/ore_granule/imgs/1204-backgrond/back.bmp");
    
    
    
    	Mat src_img(img_rows,img_cols,CV_8UC3);
    	for(int ind=1;ind!=6;ind++)
    	{
    		cout<<"proceed "<<ind<<endl;
    		sprintf(src_folder,"/home/jumper/Ore_projects/ore_granule/imgs/1204/22db_%d.bmp",ind);
    		src_img=imread(src_folder);
    		src_img=background_img-src_img;
    		cvtColor(src_img,src_img,CV_BGR2HSV);
    		vector<Mat> hsvmats(3);
    		split(src_img,hsvmats);
    		Mat vimg=hsvmats[2];
    		threshold(vimg,vimg,110,255,CV_THRESH_BINARY);
    		medianBlur(vimg,vimg,blurwidth);
    //		sprintf(dst_folder,"/home/jumper/Ore_projects/ore_granule/1204result/%d.jpg",ind);
    //		imwrite(dst_folder,vimg);
    
    		Mat contours_img(img_rows,img_cols,CV_8UC1,Scalar(0));
    		vector<vector<Point> > contours;
    		findContours( vimg, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE );
    		cv::Rect rectangle;
    		Mat contours_img2(img_rows,img_cols,CV_8UC1,Scalar(0));
    		for (int i = 0; i< contours.size(); i++)
    		{
    			contours_img2.setTo(Scalar(0));
    			vector<Point> pts;
    			vector<Point> result;
    			double area=cv::contourArea(contours[i]);
    			if(area<490)
    			{
    				continue;
    			}
    			cv::drawContours(contours_img,contours,i,Scalar(255),CV_FILLED);
    			cv::drawContours(contours_img2,contours,i,Scalar(255),CV_FILLED);
    
    
    			rectangle=cv::boundingRect(contours[i]);
    			if(area<44000)
    			{
    				cv::rectangle(contours_img,rectangle,Scalar(255),2);
    				continue;
    			}
    
    
    			Mat distance_img(rectangle.height,rectangle.width,CV_32FC1);
    			distanceTransform(contours_img2,distance_img,CV_DIST_L2,3);
    
    			vector<Point> peakpts;
    			localMaxima(distance_img,70,80,peakpts);
    			if(peakpts.size()==0)
    			{
    				continue;
    			}
    			Mat peakimgs(img_rows,img_cols,CV_8UC1,Scalar(0));
    			cout<<"peak num: "<<peakpts.size()<<endl;
    			for(int index=0;index<=peakpts.size();index++)
    			{
    				circle(peakimgs,peakpts[index],5,Scalar(255),2);
    			}
    
    			int col_left=rectangle.x;
    			int col_right=rectangle.x+rectangle.width;
    			int row_up=rectangle.y;
    			int row_bottom=rectangle.y+rectangle.height;
    			for(int index=0;index!=peakpts.size();index++)
    			{
    				int row=peakpts[index].y;
    				int col=peakpts[index].x;
    
    				int col_left_distance=col-col_left;
    				int col_right_distance=col_right-col;
    				int row_up_distance=row-row_up;
    				int row_bottom_distance=row_bottom-row;
    				int rect_height=min(row_up_distance,row_bottom_distance);
    				int rect_width=min(col_left_distance,col_right_distance);
    				cv::Point start_pt(col-rect_width,row-rect_height);
    				cv::Point end_pt(col+rect_width,row+rect_height);
    				cv::rectangle(contours_img,start_pt,end_pt,Scalar(255),2);
    				circle(contours_img,peakpts[index],5,Scalar(0),2);
    			}
    		}
    		sprintf(dst_folder,"/home/jumper/Ore_projects/ore_granule/1204result/%d_rect.jpg",ind);
    		imwrite(dst_folder,contours_img);
    
    	}
    	return 0;
    }
    
    void localMaxima(Mat src,const int maxZeroSize,const double minPeakValue,vector<Point> &maxLocpts)
    {
        double minVal=0,maxVal=0,diff=0;
        Point minLocPt,maxLocPt;
    
        minMaxLoc(src,&minVal,&maxVal,&minLocPt,&maxLocPt);//计算最大值
    
        while(maxVal>minPeakValue)
    	{
        	maxLocpts.push_back(maxLocPt);
    		Mat rect_part = src(Rect(maxLocPt.x-maxZeroSize,maxLocPt.y-maxZeroSize,2*maxZeroSize,2*maxZeroSize));
    		rect_part.setTo(Scalar(0));
    		//imwrite("temp_peak.jpg",src);
    		minMaxLoc(src,&minVal,&maxVal,&minLocPt,&maxLocPt);//计算极大值
    	}
    }
    

     

     

     

     

     

    黑色的圈是peak点:

     

    这是结果。

     

     

     

     

    但可能阈值等还要调整,效果还不够好:

    这样子不够准确而且有的会有丢失。。。

    我再想想。。。

     

     

    路漫漫。。。

    今天调整了下值:

    not enough...

     

    不稳妥。。。

    修改后:

    但如果有大量粘连的情况还是不够好,当大量粘连时我的质心点会有点多,也就是这个距离变换还不够。。。还要不断改善。

     

     

     

     

    今天是2019.2.18,看到了一种改善的分水岭效果:

    同时发现分水岭来切割粘连图像比较适合于目标差不多大小的情况,如果大小相差悬殊,则不适合,分割不开!

    看这幅图虽然右边不是最后的结果,但也是结果的原型,可以看到有的分割开的都是因为目标相差不大,而分割不开的基本都是

    要么粘连特别紧密,要么粘连没有那么紧密但是大小相差较大

    调节抑制局部极小值后:还是有分不开的很多。

    bw0 = imread('G:\src.png');
    %bw=imdilate(bw0,ones(3));
    bw=im2bw(bw0);
    imshow(bw,[]);
    D = -bwdist(~bw);
    figure;
    imshow(D,[]);
    mask = imextendedmin(D,2);
    figure;
    imshow(mask,[]);
    imshowpair(bw,mask,'blend');
    D2 = imimposemin(D,mask);
    Ld2 = watershed(D2);
    bw3 = bw;
    bw3(Ld2 == 0) = 0;
    figure;
    imshow(bw3);

    等等,我发现一个地方我错了,对于函数imextendedmin(D,4).我以为是对距离变换后的图像D,对每一个连通域,取其数值整数大于前4个的置1.结果发现不是!!

    imextendedmin(D,4).的结果是这样,看我用笔画出来的这个连通域,这个连通域的数值是:

    看数值,这个连通域经过这个函数后应该大于4、5、6、7的值位置都置1,也就是这个大的连通域应该被分为2个小的置1的块。但经过这个函数后的结果是:

    结果只有1个小块,所以也就是我用笔画出来的那样,所以后面用分水岭也是分不开这个粘连体的。

    所以我要改造一下这个函数,让它按我以为的那样实现。得到类似各个石头的核心区域mask。

    1:然后我看了一下函数D2=imimposemin(D,mask);的源码,这个函数的意思是:强制最小。D是距离变换结果,令fm=mask;且fm核心区域即为1的地方全部置为-Inf即负无穷大;为0的地方置为正无穷大Inf;

    2:距离变换图像D的最大值max-最小值min的绝对值为range,如果range不等于0,则h=range*0.001;否则为0.1;

    3:修改距离变换的结果fp1=D+h 即给距离变换的值都加上常数h。注意Matlab的距离变换结果是负数D的值都是负的。如果转opencv要注意;

    4:g=min(fp1,fm);所以此时图像g中要么是负无穷大代表的每个目标的核心区域,要么就是别的数值代表的背景以及目标的边缘包含粘连边缘;

    5:对fm取反得到fm2,对g取反得到g2;g2=1-g;

    6:对fm2,g2,以8连通域做形态学重建J=imreconstruct(fm2,g2,8);这个函数我追源码追不下去了,只看到J根g2其实差不多,但也有差别,这个差别就是形态学重建导致的,而形态学重建究竟是怎么实现的 我不知道!?

    7:Ld2=1-J; 对Ld2进行分水岭 。Ld3=watershed(Ld2);即Ld3==0的位置就是各个粘连目标的分界线;其它都是正整数表示不同的区域。

    8:对于最原始的粘连图像bw(Ld3==0)=0;这样就分开了粘连目标。

    但opencv的实现我还在写。

    展开全文
  • 今天介绍基于区域的分割方法,前面基于阈值的分割方法暂时告一段落,基于区域的分割运用同样广泛,但和阈值比较,区域分割难度也稍微大了一些,比如后面要讲到的分水岭算法,分水岭算法是个算法族,并不是单一的一个...

    weixingongzhonghao.jpg
    学习DIP第58天
    转载请标明本文出处:http://blog.csdn.net/tonyshengtan ,出于尊重文章作者的劳动,转载请标明出处!文章代码已托管,欢迎共同开发:https://github.com/Tony-Tan/DIPpro
    更多图像处理机器学习内容请访问最新网站www.face2ai.com
    #开篇废话
    继续说废话,昨天写博客被同事看到了,问我,为什么你每一篇开始都是废话,我说凑字数,在一个可以写点轻松的话,天天在算法的海洋里飘荡,偶尔说几句荒山野岭的废话也算活跃气氛了。
    #区域分割介绍
    今天介绍基于区域的分割方法,前面基于阈值的分割方法暂时告一段落,基于区域的分割运用同样广泛,但和阈值比较,区域分割难度也稍微大了一些,比如后面要讲到的分水岭算法,分水岭算法是个算法族,并不是单一的一个固定算法,比如有基于形态学的,也有基于其他的,但思想都一样,分水岭是那种典型的,看起来很简单,一说原理,小学生都能听懂,但实现起来难度不小,也可能是我代码能力不行,反正写了将近一整天,修改了一天才算看到点结果。
    由于基于区域的分割算法已经成为一个专门的研究领域,这几篇博文只介绍一点点最基础的,通用的算法,至于高深的高科技的算法,留到未来的某个时刻。这里只讲最简单的。
    今天介绍的区域生长,是其中比较简单的一种。
    #区域生长算法
    内容迁移至http://www.face2ai.com/DIP-7-8-灰度图像-图像分割-区域分割之区域生长/

    http://www.tony4ai.com/DIP-7-8-灰度图像-图像分割-区域分割之区域生长/

    展开全文
  • 区域生长(基于区域的图像分割)

    千次阅读 2014-05-08 14:51:16
    区域增长方法是根据同一物体区域内象素的相似性质来聚集象素点的方法,从初始区域(如小邻域或甚至于每个象素)开始,将相邻的具有同样性质的象素或其它区域归并到目前的区域中从而逐步增长区域,直至没有可以归并的...

    转自:http://blog.csdn.net/bagboy_taobao_com/article/details/5666091

    1. 区域生长

    区域增长方法是根据同一物体区域内象素的相似性质来聚集象素点的方法,从初始区域(如小邻域或甚至于每个象素)开始,将相邻的具有同样性质的象素或其它区域归并到目前的区域中从而逐步增长区域,直至没有可以归并的点或其它小区域为止。区域内象素的相似性度量可以包括平均灰度值、纹理、颜色等信息。

         区域增长方法是一种比较普遍的方法,在没有先验知识可以利用时,可以取得最佳的性能,可以用来分割比较复杂的图象,如自然景物。但是,区域增长方法是一种迭代的方法,空间和时间开销都比较大。

     

    区域生长是一种串行区域分割的图像分割方法。区域生长是指从某个像素出发,按照一定的准则,逐步加入邻近像素,当满足一定的条件时,区域生长终止。区域生长的好坏决定于1.初始点(种子点)的选取。2.生长准则。3.终止条件。区域生长是从某个或者某些像素点出发,最后得到整个区域,进而实现目标的提取。

    区域生长的原理

    区域生长的基本思想是将具有相似性质的像素集合起来构成区域。具体先对每个需要分割的区域找一个种子像素作为生长起点,然后将种子像素和周围邻域中与种子像素有相同或相似性质的像素(根据某种事先确定的生长或相似准则来判定)合并到种子像素所在的区域中。将这些新像素当作新的种子继续上面的过程,直到没有满足条件的像素可被包括进来。这样一个区域就生长成了。

     图1给出已知种子点进行区域生长的一个示例。图1(a)给出需要分割的图像,设已知两个种子像素(标为深浅不同的灰色方块),现要进行区域生长。设这里采用的判定准则是:如果考虑的像素与种子像素灰度值差的绝对值小于某个门限T,则将该像素包括进种子像素所在的区域。图1(b)给出了T=3时的区域生长结果,整幅图被较好地分成2个区域;图1(c)给出了T=1时的区域生长结果,有些像素无法判定;图1(c)给出了T=6时的区域生长的结果,整幅图都被分在一个区域中了。由此可见门限的选择是很重要的

     

    区域生长是一种古老的图像分割方法,最早的区域生长图像分割方法是由Levine等人提出的。该方法一般有两种方式,一种是先给定图像中要分割的目标物体内的一个小块或者说种子区域(seed point),再在种子区域基础上不断将其周围的像素点以一定的规则加入其中,达到最终将代表该物体的所有像素点结合成一个区域的目的;另一种是先将图像分割成很多的一致性较强,如区域内像素灰度值相同的小区域,再按一定的规则将小区域融合成大区域,达到分割图像的目的,典型的区域生长法如T. C. Pong等人提出的基于小面(facet)模型的区域生长法,区域生长法固有的缺点是往往会造成过度分割,即将图像分割成过多的区域

     

     

    区域生长实现的步骤如下:

    1. 对图像顺序扫描!找到第1个还没有归属的像素, 设该像素为(x0, y0);

    2. 以(x0, y0)为中心, 考虑(x0, y0)的4邻域像素(x, y)如果(x0, y0)满足生长准则, (x, y)(x0, y0)合并(在同一区域内), 同时将(x, y)压入堆栈;

    3. 从堆栈中取出一个像素, 把它当作(x0, y0)返回到步骤2;

    4. 当堆栈为空时!返回到步骤1;

    5. 重复步骤1 - 4直到图像中的每个点都有归属时。生长结束。

     

     

    代码:

    /*************************************************************************

     *

     * /函数名称:

     *   RegionGrow()

     *

     * /输入参数:

     *   CDib * pDib                     - 指向CDib类的指针,含有原始图象信息

     *   unsigned char * pUnRegion       - 指向区域生长结果的指针

     *

     * /返回值:

     *   

     *

     * /说明:

     *   pUnRegion指针指向的数据区存储了区域生长的结果,其中(逻辑)表示

     *   对应象素为生长区域,表示为非生长区域

     *   区域生长一般包含三个比较重要的问题:

     *       1. 种子点的选取

     *       2. 生长准则

     *       3. 终止条件

     *   可以认为,这三个问题需要具体分析,而且每个问题解决的好坏直接关系到

     *   区域生长的结果。

     *   本函数的种子点选取为图像的中心,生长准则是相邻象素的象素值小于

     *   nThreshold, ()终止条件是一直进行到再没有满足生长准则需要的象素时为止

     *   

     *************************************************************************

     */

    // 在这个代码中,它认为这张图片就是一个区域,选取了中间点为种子点。

    void RegionGrow(CDib * pDib, unsigned char * pUnRegion, int nThreshold)

    {

         static int nDx[]={-1,0,1,0};

         static int nDy[]={0,1,0,-1};

     

         nThreshold = 20;

     

         // 遍历图象的纵坐标

    //   int y;

     

         // 遍历图象的横坐标

    //   int x;

     

         // 图象的长宽大小

         CSize sizeImage        = pDib->GetDimensions();

         int nWidth             = sizeImage.cx         ;

         int nHeight            = sizeImage.cy         ;

     

         // 图像在计算机在存储中的实际大小

         CSize sizeImageSave    = pDib->GetDibSaveDim();

     

         // 图像在内存中每一行象素占用的实际空间

         int nSaveWidth = sizeImageSave.cx;

     

         // 初始化

         memset(pUnRegion,0,sizeof(unsigned char)*nWidth*nHeight);

     

         // 种子点

         int nSeedX, nSeedY;

     

         // 设置种子点为图像的中心

         nSeedX = nWidth /2 ;

         nSeedY = nHeight/2 ;

     

         // 定义堆栈,存储坐标

         int * pnGrowQueX ;

         int * pnGrowQueY ;

        

         // 分配空间

         pnGrowQueX = new int [nWidth*nHeight];

         pnGrowQueY = new int [nWidth*nHeight];

     

         // 图像数据的指针

         unsigned char *  pUnchInput =(unsigned char * )pDib->m_lpImage;

        

         // 定义堆栈的起点和终点

         // 当nStart=nEnd, 表示堆栈中只有一个点

         int nStart ;

         int nEnd   ;

     

         //初始化

         nStart = 0 ;

         nEnd   = 0 ;

     

         // 把种子点的坐标压入栈

         pnGrowQueX[nEnd] = nSeedX;

         pnGrowQueY[nEnd] = nSeedY;

     

         // 当前正在处理的象素

         int nCurrX ;

         int nCurrY ;

     

         // 循环控制变量

         int k ;

     

         // 图象的横纵坐标,用来对当前象素的邻域进行遍历

         int xx;

         int yy;

     

         while (nStart<=nEnd)

         {

             // 当前种子点的坐标

             nCurrX = pnGrowQueX[nStart];

             nCurrY = pnGrowQueY[nStart];

     

             // 对当前点的邻域进行遍历

             for (k=0; k<4; k++)   

             {   

                  // 4邻域象素的坐标

                  xx = nCurrX + nDx[k];

                  yy = nCurrY + nDy[k];

                 

                  // 判断象素(xx,yy) 是否在图像内部

                  // 判断象素(xx,yy) 是否已经处理过

                  // pUnRegion[yy*nWidth+xx]==0 表示还没有处理

     

                  // 生长条件:判断象素(xx,yy)和当前象素(nCurrX,nCurrY) 象素值差的绝对值

                  if ( (xx < nWidth) && (xx>=0) && (yy<nHeight) && (yy>=0)

                           && (pUnRegion[yy*nWidth+xx]==0)

                           && abs(pUnchInput[yy*nSaveWidth+xx] - pUnchInput[nCurrY*nSaveWidth+nCurrX])<nThreshold )

                  {

                       // 堆栈的尾部指针后移一位

                       nEnd++;

     

                       // 象素(xx,yy) 压入栈

                       pnGrowQueX[nEnd] = xx;

                       pnGrowQueY[nEnd] = yy;

     

                       // 把象素(xx,yy)设置成逻辑()

                       // 同时也表明该象素处理过

                       pUnRegion[yy*nWidth+xx] = 255 ;

                  }

             }

             nStart++;

         }

     

         // 释放内存

         delete []pnGrowQueX;

         delete []pnGrowQueY;

        pnGrowQueX = NULL ;

         pnGrowQueY = NULL ;

    }

     

    该代码的效果不是很好,大概是选择的生长点不是很好吧。

    展开全文
  • 通过非Vlink方法实现非骨干区域与骨干区域互通试验拓扑: R2的配置:interface Tunnel0/0/0 ip address 1.1.1.1 255.255.255.0 tunnel-protocol gre source 10.0.23.2 destination 10.0.23.3ospf 1 ...

    通过非Vlink方法实现非骨干区域与骨干区域互通

    试验拓扑:
    这里写图片描述
    R2的配置:

    interface Tunnel0/0/0
    ip address 1.1.1.1 255.255.255.0
    tunnel-protocol gre
    source 10.0.23.2
    destination 10.0.23.3

    ospf 1 router-id 10.0.2.2
    area 0.0.0.0
    network 10.0.2.2 0.0.0.0
    network 10.0.12.0 0.0.0.255
    network 1.1.1.0 0.0.0.255
    area 0.0.0.1
    network 10.0.23.0 0.0.0.255
    vlink-peer 10.0.1.1
    vlink-peer 10.0.3.3

    R3的配置:

    interface Tunnel0/0/1
    ip address 1.1.1.2 255.255.255.0
    tunnel-protocol gre
    source 10.0.23.3
    destination 10.0.23.2

    ospf 1 router-id 10.0.3.3
    area 0.0.0.0
    network 1.1.1.0 0.0.0.255
    area 0.0.0.1
    network 10.0.3.3 0.0.0.0
    network 10.0.23.0 0.0.0.255
    network 10.0.13.0 0.0.0.255
    area 0.0.0.2
    network 10.0.34.0 0.0.0.255

    这里写图片描述

    展开全文
  • 此外,中国联通发布了“7+33+n”5G试验网络部署,即在7座城市核心区域连续覆盖,在33座城市的热点区域和X座城市行业应用区域提供5G网络覆盖,为合作伙伴提供更为广阔的试验场景,推进5G应用孵化及产业升级。...
  • 试验机软件报表设计

    2009-04-03 08:51:00
     试验机软件报表大多为封闭式报表,类似于常用的Excel电子表格,这样一张报表可以具体分割为一个个单元格(数据区域),每个单元格表现为:1. 单元格边框线单元格边框线需要考虑线条位置、线条样式、线条颜色、...
  • 最近在学习图像分割的方法,所以对区域生长与区域分离与合并的图像分割方法进行一下总结。 首先说一下两者的不同。区域生长是根据预先定义的生长准则来把像素或子区域集合成较大区域的处理方法。区域生长是先给定...
  • 华为eNSP OSPF验证试验

    千次阅读 2020-06-02 16:03:01
    3、既支持vlsm 可变掩码、又支持 cidr(无类别域间选路) 4、封装 layer2| ip |ospf| fcs 直接封装到IP报头内 上层协议号为89 eigrp为88 开始实验 OSPF验证试验 实验案列:使用eNSP验证OSPF优先级 实验环境 B公司...
  • 太美eCooperate(简称CCP)是基于多方协作的临床研究项目管理云平台,是对原有CTMS临床试验项目管理系统的全新升级,提供标准的临床试验项目进度编排模板,使之最大限度地符合临床试验的GCP法规,最大限度地规范临床...
  • 试验三:MicaZ-TinyOS2.x平台下点对点通讯试验 ——BlinktoRadio实验    试验目的:本节介绍TinyOS中的无线通信。能够熟练使用TinyOS支持通信的接口和组件,并且我们可以学习到: 1).TinyOS2.0消息缓存message...
  • 区域生长与分裂合并

    千次阅读 2020-01-11 13:22:01
    区域生长需要选择一组能正确代表所需区域的种子像素,确定在生长过程中的相似性准则,制定让生长停止的条件或准则。相似性准则可以是灰度级、彩色、纹理、梯度等特性。选取的种子像素可以是单个像素,也可以是包含...
  • 首批试运行的分群包含11个行业分群、6个区域分群、1个项目助选团分群以及5个KOL分群。7月12日,币改试验区发布了6号公告,公布了第一批试运行的分群及群主信息。据公告所...
  • Echart中设置分割区域

    千次阅读 2019-05-21 09:43:42
    最近碰到一个需求横向绘制区域,用不同颜色进行分割,刚开始用的areaStyle,最后发现对于负数等情况不能很好适应,最终通过研究和百度发现了markArea的方法,特此分享,直接上代码, 这个网址...
  • 华为USG防火墙区域配置

    千次阅读 2017-11-27 17:30:00
    学习目的 掌握防火墙安全区域的配置方法 ...公司总部的网络分成了三个区域,包括内部区域(Trust)外部区域(Untrust)和服务器区域(DMZ)。现在设计通过防火墙来实现对数据的控制。在交换机上将G0/0/1与G...
  • eNSP防火墙安全区域实验

    千次阅读 2020-03-02 11:18:36
    ============================================================================================== 2020/2/18 三叶草 实验拓扑: ...3. trust区域所有地址均能连通untrust区域 4. untrust区域只能访问...
  • 中新网成都6月9日电(记者 杨杰)记者今天获悉,国务院已正式批准重庆市和成都市设立全国统筹城乡综合配套改革试验区,这是中国在新的历史时期加快中西部发展,推动区域协调发展的重大战略部署。 6月7日,国家发展和...
  •  我们知道,区域类型一共有三种,即主要区域 、辅助区域和存根区域,本节会针对辅助区域和存根区域的操作进行演示。 辅助区域操作演示 1、安装配置主DNS区域  辅助区域是以主要区域为蓝本,复制出一个相同,且...
  • 大数据产业创新服务媒体 ——聚焦数据 · 改变商业 2020年9月21日,国务院公布了北京、湖南、安徽三个自贸试验区总体方案及浙江自贸试验区扩展区域方案。至此,中国自贸试验区覆盖21个省级行政区域,片区数量达到70...
  • 关于模板缓存的一些试验

    千次阅读 2009-12-26 20:50:00
    它和深度缓存比较像(可以理解为“某区域的深度缓存”,个人意见,呵呵~~)。OK,一切都明白了。(至于函数的使用及参数意义,可以参考上面的网址链接或红宝书) 其次,有时我们是不需要显示这个MASK的。使用过...
  • OSPF特殊区域Stub配置实验及简单对比

    千次阅读 2019-10-20 17:38:13
    一、实验目的 1、掌握OSPF动态路由协议的定义和功能;...1、绘制拓扑图,根据拓扑图进行试验: 2、配置路由器,并最终验证网络的连通性。 三、实验流程 (一)配置任务说明 实验拓扑: 由图知: 该实验分为...
  • 今天宣布的这一消息标志着日本金融机构和技术部门将接受和试验区块链技术。 随着这消息的宣布,信息技术咨询服务公司NTT Data将与数字货币初创公司Orb及其他公司一起合作研究该技术。 参与该项目的Orix和Shiz
  • 今天继续试验十分钟可以干什么,选取了对Oracle索引的介绍,结果如下: 从google上寻找资料:1:15秒。 阅读概述部分:3:15秒。 Oracle的索引主要包含两类:BTree和位图索引。默认情况下大多使用Btree索引,该索引...
  • CBM 2099 OTG扩容U盘量产,亲自试验经验 前段时间在某宝(大家都懂得)买了一个128G U盘,当时原以为性价比很高,拿到手才发现是扩容U盘,真实一分钱一分货。我的实例也告诉我们,不要贪图小便宜,否则会让你花很大...
  • 第二个试验:用单片机点亮一个闪烁的发光管一次我们的程序实在是没什么用,要灯亮还要重写一下片子,下面我们要让灯不断地闪烁,这就有一定的实用价值了,比如可以把它当成汽车上的一个信号灯用了。怎样才能让灯不断...
  • OSPF多区域(实验)

    千次阅读 2019-07-20 15:02:57
    掌握多区域OSPF的配置方法 掌握OSPF区域之间路由汇总的配置方法 掌握OSPF参考宽带的配置方法 掌握OSPF引入外部路由的配置方法 掌握握OSPF引入的外部路由时进行路由汇总的方法 掌握向OSPF导入缺省路由的方法 ...
  • Buffon投针试验【布丰】

    千次阅读 2009-10-29 13:01:00
    计算某一区域内的随机浮点数 @param a 区域的下边界 @param b 区域的上边界 @return 随机浮点数x,x∈[a,b] */ double rand_double(double a,double b) { return a+(b-a)*rand()*1.0/RAND_MAX; } ...
  •  打开桌面的火狐浏览器,进入主界面右键点击上方任务栏的空白区域,在属性框里选择【Menu Bur(菜单栏)】选项  然后我们在上方任务栏就可以看到【菜单栏选项】,点击【tools(工具)】  在弹出的tool...
  • 7月9日,币改试验区筹备组已经完成了一轮投票,通过了16位新成员,当前群成员总数26人。今日启动第二轮投票的前期准备工作。我们欢迎热心通证经济实践的社会各界有识之士继续报...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 46,406
精华内容 18,562
关键字:

区域试验