【数字图像处理】求图像rice.png中米粒个数

 图像处理课程上老师布置的任务,要求求出图片rice.png中米粒的个数及其各米粒的大小。

rice.png:


大体步骤是:首先进行边缘检测,然后进行填充。然后进行开运算,可以使一些轻微连着的米粒分开来。然后是遍历图片,把各米粒进行标号,从1开始从小到大标号。每个米粒的各像素点值相同,第i个米粒的各像素点值均为i。其中采用了队列,用数组模拟。最大的米粒标号便是米粒的总个数。最后,遍历一遍图像数组,便可求出各米粒的面积。

参考代码(matlab实现):

clear; close all; I = imread('rice.png'); [width,height] = size(I); J = edge(I,'canny'); %figure,imshow(J); K = imfill(J,'holes'); %figure,imshow(K); SE = strel('disk',3);%用于膨胀腐蚀及开闭运算等操作的结构元素对象 %对图像实现开运算,开运算一般能平滑图像的轮廓,消弱狭窄的部分,去掉细的突出。 L = imopen(K,SE); figure,imshow(L); L = uint8(L);%把L由logic类型转化为uint8类型 for i = 1:height for j = 1:width if L(i,j) == 1 L(i,j) = 255;%把白色像素点像素值赋值为255 end end end MAXSIZE = 999999; Q = zeros(MAXSIZE,2);%用数组模拟队列,存储像素点坐标 front = 1;%指明队头的位置 rear = 1;%指明队尾的下一个位置;front=rear表示队空 flag = 0;%米粒的标号 for i = 1:height for j = 1:width if L(i,j) == 255%白色像素点入队列 if front == rear%队列空,找到新米粒,米粒标号加一 flag = flag+1; end L(i,j) = flag;%给白色像素赋值为米粒的标号 Q(rear,1) = i; Q(rear,2) = j; rear = rear+1;%队尾后移 while front ~= rear %队头出队 temp_i = Q(front,1); temp_j = Q(front,2); front = front + 1; %把队头位置像素点8连通邻域中未作标记的白色像素点入队,并加上米粒标号 %左上角的像素点 if L(temp_i - 1,temp_j - 1) == 255 L(temp_i - 1,temp_j - 1) = flag; Q(rear,1) = temp_i - 1; Q(rear,2) = temp_j - 1; rear = rear + 1; end %正上方的像素点 if L(temp_i - 1,temp_j) == 255 L(temp_i - 1,temp_j) = flag; Q(rear,1) = temp_i - 1; Q(rear,2) = temp_j; rear = rear + 1; end %右上方的像素点 if L(temp_i - 1,temp_j + 1) == 255 L(temp_i - 1,temp_j + 1) = flag; Q(rear,1) = temp_i - 1; Q(rear,2) = temp_j + 1; rear = rear + 1; end %正左方的像素点 if L(temp_i,temp_j - 1) == 255 L(temp_i,temp_j - 1) = flag; Q(rear,1) = temp_i; Q(rear,2) = temp_j - 1; rear = rear + 1; end %正右方的像素点 if L(temp_i,temp_j + 1) == 255 L(temp_i,temp_j + 1) = flag; Q(rear,1) = temp_i; Q(rear,2) = temp_j + 1; rear = rear + 1; end %左下方的像素点 if L(temp_i + 1,temp_j - 1) == 255 L(temp_i + 1,temp_j - 1) = flag; Q(rear,1) = temp_i + 1; Q(rear,2) = temp_j - 1; rear = rear + 1; end %正下方的像素点 if L(temp_i + 1,temp_j) == 255 L(temp_i + 1,temp_j) = flag; Q(rear,1) = temp_i + 1; Q(rear,2) = temp_j; rear = rear + 1; end %右下方的像素点 if L(temp_i + 1,temp_j + 1) == 255 L(temp_i + 1,temp_j + 1) = flag; Q(rear,1) = temp_i + 1; Q(rear,2) = temp_j + 1; rear = rear + 1; end end end end end figure,imshow(L); RiceNumber = flag;%记录米粒的总个数 disp('米粒的总个数:') RiceNumber RiceArea = zeros(1,RiceNumber);%记录各米粒的大小 for i = 1:height for j = 1:width if L(i,j) ~= 0 RiceArea(L(i,j)) = RiceArea(L(i,j)) + 1; end end end disp('各米粒的大小(按照从上往下,从左往右的顺序):') RiceArea


运行结果:

边缘检测,填充,开运算之后的结果:


可以看出有些轻微连着的米粒被分开了。

进行标号后的结果:


米粒是从上到下从左到右依次编号的。从图中米粒的明暗程度可以看出来。

最终结果:

米粒的总个数:


RiceNumber =


    69


各米粒的大小(按照从上往下,从左往右的顺序):


RiceArea =


  Columns 1 through 20


   212   146   197   179   224   431   208   182   147   189   236   214   207   202   138   188   158   202   210   181


  Columns 21 through 40


   186   211   199   227   203   223   224   227   249   254   225   187   183   200   232   199   210   200   198   183


  Columns 41 through 60


   230   268   233   235   193   206   240   158   207   215   238   200   239   227   207   254   237   203   211   236


  Columns 61 through 69


   219   152   225   238   169   223   215   195   195

 有一个比较简单的方法是直接调用bwlabel函数,进行连通域标记。不过老师要求尽量不要调用这些库函数,自己把他实现出来,这样理解的深刻一些,更好地提高编程能力。

clear; close all; I=imread('rice.png'); %imshow(I); J=edge(I,'canny'); %figure,imshow(J); K=imfill(J,'holes'); figure,imshow(K); SE=strel('disk',3);%用于膨胀腐蚀及开闭运算等操作的结构元素对象 %对图像实现开运算,开运算一般能平滑图像的轮廓,消弱狭窄的部分,去掉细的突出。 L=imopen(K,SE); figure,imshow(L); M=bwlabel(L,4);%8联通域标记 figure,imshow(M,[]); %矩阵M的大小 [m,n]=size(M); num=0;%米粒的个数 for i=1:m for j=1:n if M(i,j)>num%最大的label值即联通域的个数 num=M(i,j); end end end area=zeros(1,num);%记录各个米粒的大小 for i=1:m for j=1:n if M(i,j)>0%不是背景,在联通域里面 area(1,M(i,j))=area(1,M(i,j))+1;%对应的米粒大小加一 end end end disp('米粒个数:'); disp(num); disp('各个米粒的大小'); area

转载于:https://www.cnblogs.com/xiajun/archive/2011/10/27/2298640.html

你可能感兴趣的:(【数字图像处理】求图像rice.png中米粒个数)