图像处理 计数_matlab图像处理车辆计数 - CSDN
  • matlab图像处理关于细胞计数

    万次阅读 多人点赞 2018-02-28 19:32:35
    第1章 问题重述本题共给出了如下所示的二十五张图片,每张图片都是显微镜下对运动精子静态观察的微观显示,每张图片中都含有很多条精子,随机选取一张精子的静态图片,以第十张图片为例,从图片1-2中可以看出,精子...

    第1章 问题重述

    本题共给出了如下所示的二十五张图片,每张图片都是显微镜下对运动精子静态观察的微观显示,每张图片中都含有很多条精子,随机选取一张精子的静态图片,以第十张图片为例,从图片1-2中可以看出,精子的分布具有不均匀性,其分布毫无规律,十分散乱,精子的游动方向各不相同,其尾部有的张开,也有的和头部重合,且背景以灰色为主,还有白色等混杂的颜色。本题要求在这样混杂的二十五张图片中求出每张图内所含的精子数目。   

                             

                                 图1-1 二十五张精子图

           

    图1-2 第十张精子图

    第2章 设计方案

    2.1 解决思路

    从所给的图片中,我们可以看到黑色的精子,灰白相间的背景,对于这样的看似只有黑白灰的图像,实则并不是灰度图像,所以首先要对图像进行灰度处理,将图像变成灰度值介于0-255之间的数,然后构造结构元素,将精子的轮廓选中,去除不均匀背景,调节灰度的对比度,最后将灰度图像二值化,标记二值化图像中的元素,即可得到一副图片中精子数量,若求取二十五幅图片中精子数量,可利用循环结构,将其求出。

    2.2 设计流程

                  

    图2-1 设计流程图

    2.3 原理介绍

    2.3.1灰度处理

    灰度数字图像是每个像素只有一个采样颜色的图像。这类图像通常显示为从最暗黑色到最亮的白色的灰度,尽管理论上这个采样可以任何颜色的不同深浅,甚至可以是不同亮度上的不同颜色。灰度图像与黑白图像不同,在计算机图像领域中黑白图像只有黑白两种颜色,灰度图像在黑色与白色之间还有许多级的颜色深度。

    一幅完整的图像,是由红色、绿色、蓝色三个通道组成的。红色、绿色、蓝色三个通道的缩览图都是以灰度显示的。用不同的灰度色阶来表示“ 红,绿,蓝”在图像中的比重。通道中的纯白,代表了该色光在此处为最高亮度,亮度级别是255。

    在计算机领域中,这类图像通常显示为从最暗黑色到最亮的白色的灰度,尽管理论上这个采样可以任何颜色的不同深浅,甚至可以是不同亮度上的不同颜色。灰度图像与黑白图像不同,在计算机图像领域中黑白图像只有黑色与白色两种颜色;灰度图像在黑色与白色之间还有许多级的颜色深度。但是,在数字图像领域之外,“黑白图像”也表示“灰度图像”,例如灰度的照片通常叫做“黑白照片”。

    我们可以通过下面几种方法,将其转换为灰度:

    1.浮点算法:Gray=R*0.3+G*0.59+B*0.11

    2.整数方法:Gray=(R*30+G*59+B*11)/100

    3.移位方法:Gray =(R*76+G*151+B*28)>>8;

    4.平均值法:Gray=(R+G+B)/3;

    5.仅取绿色:Gray=G;

    通过上述任一种方法求得Gray后,将原来的RGB(R,G,B)中的R,G,B统一用Gray替换,形成新的颜色RGB(Gray,Gray,Gray),用它替换原来的RGB(R,G,B)就是灰度图了。


    图2-2 灰度处理效果对比图

    2.3.2 构造结构元素

    构造结构元素是利用膨胀、腐蚀、开运算、闭运算等方法对图像进行处理,膨胀和腐蚀这两种操作是形态学处理的基础,许多形态学算法都是以这两种运算为基础的.
    1.膨胀
             是以得到B的相对与它自身原点的映像并且由z对映像进行移位为基础的.A被B膨胀是所有位移z的集合,这样,和A至少有一个元素是重叠的.结构元素B可以看作一个卷积模板,区别在于膨胀是以集合运算为基础的,卷积是以算术运算为基础的,但两者的处理过程是相似的.
    ⑴ 用结构元素B,扫描图像A的每一个像素
    ⑵ 用结构元素与其覆盖的二值图像做“与”操作
    ⑶ 如果都为0,结果图像的该像素为0.否则为1

    图2-3 膨胀原理示意图


    2.腐蚀
             对Z中的集合A和B,B对A进行腐蚀的整个过程如下:
    ⑴ 用结构元素B,扫描图像A的每一个像素
    ⑵ 用结构元素与其覆盖的二值图像做“与”操作
    ⑶ 如果都为1,结果图像的该像素为1.否则为0
             腐蚀处理的结果是使原来的二值图像减小一圈。

    3.开运算

    开运算数学上是先腐蚀后膨胀的结果,开运算的结果为完全删除了不能包含结构元素的对象区域,平滑了对象的轮廓,断开了狭窄的连接,去掉了细小的突出部分。

    4.闭运算

    闭运算在数学上是先膨胀再腐蚀的结果,闭运算的结果也是会平滑对象的轮廓,但是与开运算不同的是,闭运算一般会将狭窄的缺口连接起来形成细长的弯口,并填充比结构元素小的洞。

    图2-4 腐蚀原理示意图

    通常,由于噪声的影响,图象在阈值化后所得到边界往往是很不平滑的,物体区域具有一些噪声孔,背景区域上散布着一些小的噪声物体。连续的开和闭运算可以有效地改善这种情况。有时需要经过多次腐蚀之后再加上相同次数的膨胀,才可以产生比较好的效果。

    2.3.3灰度图像二值化

    将256个亮度等级的灰度图像通过适当的阈值选取而获得仍然可以反映图像整体和局部特征的二值化图像。在数字图像处理中,二值图像占有非常重要的地位,首先,图像的二值化有利于图像的进一步处理,使图像变得简单,而且数据量减小,能凸显出感兴趣的目标的轮廓。其次,要进行二值图像的处理与分析,首先要把灰度图像二值化,得到二值化图像。

    图像的二值化处理就是将图像上的点的灰度值为0或255,也就是将整个图像呈现出明显的黑白效果。即将256个亮度等级的灰度图像通过适当的阈值选取而获得仍然可以反映图像整体和局部特征的二值化图像。在数字图像处理中,二值图像占有非常重要的地位,特别是在实用的图像处理中,以二值图像处理实现而构成的系统是很多的,要进行二值图像的处理与分析,首先要把灰度图像二值化,得到二值化图像,这样子有利于在对图像做进一步处理时,图像的集合性质只与像素值为0或255的点的位置有关,不再涉及像素的多级值,使处理变得简单,而且数据的处理和压缩量小。为了得到理想的二值图像,一般采用封闭、连通的边界定义不交叠的区域。所有灰度大于或等于阈值的像素被判定为属于特定物体,其灰度值为255表示,否则这些像素点被排除在物体区域以外,灰度值为0,表示背景或者另外的物体区域。

    2.3.4二值图像连通域标记

        讨论连通区域标记的算法之前,我们先要明确什么是连通区域,怎样的像素邻接关系构成连通。在图像中,最小的单位是像素,每个像素周围有8个邻接像素,常见的邻接关系有2种:4邻接与8邻接。4邻接一共4个点,即上下左右,如下左图所示。8邻接的点一共有8个,包括了对角线位置的点,如下图所示:

          

    图2-5 二值图像连通域示意图

    如果像素点A与B邻接,我们称A与B连通,于是我们不加证明的有如下的结论:如果A与B连通,B与C连通,则A与C连通。在视觉上看来,彼此连通的点形成了一个区域,而不连通的点形成了不同的区域。这样的一个所有的点彼此连通点构成的集合,我们称为一个连通区域。

    现在matlab中连通区域标记函数bwlabel中使的算法,它一次遍历图像,并记下每一行或列中连续的团和标记的等价对,然后通过等价对对原来的图像进行重新标记,这个算法是标记算法中效率最高的一个。

     第3章 一张图的精子数目统计

    3.1 编程设计

    % 载入图片
    
    t=1;
    
    RGB = imread(strcat(int2str(t),'.','jpg'));
    
    figure,imshow(RGB)
    
    I = rgb2gray(RGB);
    
    se = strel('disk',20);
    
    I2 = imbothat(I,se);  % 底帽变换,去除不均匀背景
    
    figure,imshow(I2)
    
     
    
    I3 = imadjust(I2);   % 调节灰度对比度
    
     
    
    % 灰度图像二值化,全局阈值分割最大化类间方差
    
    level = graythresh(I3);
    
    BW = im2bw(I3,level);
    
    figure,imshow(BW)
    
     
    
    [L,N] = bwlabel(BW);  % N即为目标个数
    
     
    
    % 标记目标物
    
    figure,imshow(RGB)
    
    hold on
    
    for k = 1:N
    
        [r,c] = find(L == k);
    
        rbar = mean(r);
    
        cbar = mean(c);   plot(cbar,rbar,'marker','o','markeredgecolor','r','markersize',10);
    
    end
    
     
    
    % 对话框显示目标物个数
    
    h = dialog('Name','目标个数','position',[580 300 220 100]);  % 创建一个对话框窗口
    
     
    
    uicontrol('Style','text','units','pixels','position',[45 40 120 50],'fontsize',15,'parent',h,'string',strcat('第',num2str(t),'张图的精子数为',num2str(N),'个'));     % 创建文本内容
    
     
    
    uicontrol('units','pixels','position',[80 10 50 20],'fontsize',10,
    
    'parent',h,'string','确定','callback','delete(gcf)'); % 创建【确定】按钮
    
     
    3.2 统计结果

    每一步骤运行后的结果一次如下图所示:

    图3-1 第一张精子图

     

    图3-2 第一张构造结构元素后灰度处理图


    图3-3 第一张灰度二值化处理图


    图3-4 第一张目标标记图

    图3-5 第一张精子数目统计图

                          第4章 全部图片的数目统计

    4.1 编程设计

     

    % 载入图片
    
    t=1;
    
    RGB = imread(strcat(int2str(t),'.','jpg'));
    
    figure,imshow(RGB)
    
    I = rgb2gray(RGB);
    
    se = strel('disk',20);
    
    I2 = imbothat(I,se);  % 底帽变换,去除不均匀背景
    
    figure,imshow(I2)
    
     
    
    I3 = imadjust(I2);   % 调节灰度对比度
    
     
    
    % 灰度图像二值化,全局阈值分割最大化类间方差
    
    level = graythresh(I3);
    
    BW = im2bw(I3,level);
    
    figure,imshow(BW)
    
     
    
    [L,N] = bwlabel(BW);  % N即为目标个数
    
     
    
    % 标记目标物
    
    figure,imshow(RGB)
    
    hold on
    
    for k = 1:N
    
        [r,c] = find(L == k);
    
        rbar = mean(r);
    
        cbar = mean(c);   plot(cbar,rbar,'marker','o','markeredgecolor','r','markersize',10);
    
    end
    
     
    
    % 对话框显示目标物个数
    
    h = dialog('Name','目标个数','position',[580 300 220 100]);  % 创建一个对话框窗口
    
     
    
    uicontrol('Style','text','units','pixels','position',[45 40 120 50],'fontsize',15,'parent',h,'string',strcat('第',num2str(t),'张图的精子数为',num2str(N),'个'));     % 创建文本内容
    
     
    
    uicontrol('units','pixels','position',[80 10 50 20],'fontsize',10,
    
    'parent',h,'string','确定','callback','delete(gcf)'); % 创建【确定】按钮
    
     

    3.2 统计结果

     

    图4-1 第三四五六张精子数目图

    将全部的25张图片用循环算法求解出其精子数目,将其汇总如下表:

    表4-1 二十五张精子数目统计表

    第1张图

    第2张图

    第3张图

    第4张图

    第5张图

    409

    402

    391

    421

    408

    第6张图

    第7张图

    第8张图

    第9张图

    第10张图

    409

    395

    406

    410

    383

    第11张图

    第12张图

    第13张图

    第14张图

    第15张图

    396

    369

    400

    395

    395

    第16张图

    第17张图

    第18张图

    第19张图

    第20张图

    390

    400

    385

    399

    381

    第21张图

    第22张图

    第23张图

    第24张图

    第25张图

    378

    383

    395

    403

    391

     

    由此可知,将全部图片精子数目都统计了出来,本题得到了解决。

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    展开全文
  • 波点壁纸中圆点的计数 去年年末我学习了天津科技大学杨淑莹老师的《数字图像处理》课程,虽然课程有点老,但是内容还是比较经典的。课程最后有好几个数字图像处理的案例,都是基于Visual C++的,我使用Python实现...

    波点壁纸中圆点的计数

    去年年末我学习了天津科技大学杨淑莹老师的《数字图像处理》课程,虽然课程有点老,但是内容还是比较经典的。课程最后有好几个数字图像处理的案例,都是基于Visual C++的,我使用Python实现其中的“细胞个数统计”,并进行了一定的探索。杨老师的视频在哔哩哔哩和MOOC都能获取。

    解决思路:

    • 转换色彩空间至HSV
    • 根据H通道进行阈值分割
    • 中值滤波去噪
    • 腐蚀操作去除孤立的点
    • 检测所有图形的轮廓,并计数

    如果使用Python,可以选择的图像处理库有
    1、工业级的图像处理库:Opencv
    2、PIL
    3、Skimage
    我使用的是Skimage,因为它和numpy联和的比较紧密,使用较为方便,能暂时满足我基本需求。

    转换色彩空间至HSV

    我选取的图片是一张波点照片,背景和前景的照片颜色信息差别很大,因此转换到了HSV色彩空间,其中色调(H),饱和度(S),明度(V)。想利用它的色调差别,来进行前景和背景的分离。

    @adapt_rgb(each_channel)
    def median_each(image):
        return sfr.median(image, disk(3))
    
    img_path = '波点壁纸.jpg'
    img_data = io.imread(img_path)
    
    dst = median_each(img_data)
    plt.figure('filters',figsize=(20,20))
    
    plt.subplot(121)
    plt.title('origin image')
    plt.imshow(img_data)
    
    plt.subplot(122)
    plt.title('Smoothed image')
    plt.imshow(dst)

    这里写图片描述

    根据H通道进行阈值分割

    img_hsv_1 = color.rgb2hsv(dst)
    plt.imshow(img_hsv_1,plt.cm.hsv)

    这里写图片描述

    中值滤波去噪

    # H通道直方图
    img = img_hsv_1[:,:,0]
    plt.figure("hist")
    arr=img.flatten()
    plt.hist(arr, bins=256, normed=1,facecolor='r',edgecolor='r',hold=1)
    plt.show()

    这里写图片描述

    这里没有采用迭代阈值分割法或者大津法,而是通过鼠标点击获取对应位置的值,然后感性地选出阈值

    # 手动查看鼠标对应H值
    %matplotlib qt5
    loop_num = 5
    plt.imshow(img)
    pos=plt.ginput(loop_num)
    for i in range(loop_num):
        x,y = int(pos[i][1]),int(pos[i][0])
        print '第%d个点击的 x,y:' % int(i+1) ,'(', x , y,')'
        print '对应的H值为:',img[x,y],'\n'

    这里写图片描述

    # 手动选取阈值
    %matplotlib inline
    rows,cols=img.shape
    labels=np.zeros([rows,cols])
    for i in range(rows):
        for j in range(cols):
            if(img[i,j]<0.53 or img[i,j]>0.60):# 0.53 0.65
                labels[i,j]=0
            else:
                labels[i,j]=1
    shuffle =  color.rgb2gray(labels)
    io.imshow(shuffle)

    这里写图片描述

    中值滤波去噪

    # 中值滤波去噪
    shuffle_ = sfr.median(shuffle, disk(5))
    new_img = color.rgb2gray(shuffle_)
    io.imshow(new_img)

    这里写图片描述

    腐蚀操作去除孤立的点

    # 腐蚀操作,去除孤立的点
    new_img_fat = sm.erosion(new_img,sm.square(5))
    
    plt.figure('filters',figsize=(20,20))
    
    plt.subplot(131)
    plt.title('origin image')
    io.imshow(new_img)
    
    plt.subplot(132)
    plt.title('fat image')
    io.imshow(new_img_fat)
    
    plt.subplot(133)
    plt.title('fat - orgin')
    io.imshow(new_img_fat - new_img)

    这里写图片描述

    检测所有图形的轮廓,并计数

    本来应该使用细化来数出个数,但是偶然找到一个用来发现轮廓的api,取了点巧

    #检测所有图形的轮廓
    contours = measure.find_contours(new_img_fat, 0.5)
    
    #绘制轮廓
    fig, (ax0,ax1) = plt.subplots(1,2,figsize=(16,16))
    ax0.imshow(new_img_fat,plt.cm.gray)
    ax1.imshow(new_img_fat,plt.cm.gray)
    
    for n, contour in enumerate(contours):
        ax1.plot(contour[:, 1], contour[:, 0], linewidth=2)
    ax1.axis('image')
    ax1.set_xticks([])
    ax1.set_yticks([])
    plt.show()
    print '总共有多少个⭕️:',len(contours)

    这里写图片描述


    总结

    代码不难,都是skimage库的使用,当然如果有时候达不到自己想要的效果,可以自己写。主要是掌握了使用数字图像处理解决这种问题的思路,数字图像处理不同模块的内容是松耦合的,这门课是计算机视觉的基础课,它是一种工具,一般将它的知识点串行地使用来解决图像的基础问题。

    展开全文
  • 图像处理之简单综合实例(大米计数)

    万次阅读 2012-05-26 23:17:06
    图像处理之简单综合实例(大米计数) 一位网友给我发了几张灰度图像,说是他们单位的工业相机拍摄的,画质非常的清楚,他们 单位是农业科研单位,特别想知道种子的数量,他想知道的是每次工业相机拍摄种子图片中 ...

    图像处理之简单综合实例(大米计数)

    一位网友给我发了几张灰度图像,说是他们单位的工业相机拍摄的,画质非常的清楚,他们

    单位是农业科研单位,特别想知道种子的数量,他想知道的是每次工业相机拍摄种子图片中

    有多少颗粒种子,想到了用图像处理的办法解决他们的问题,看了他给我照片,以大米种子

    为例。实现了一个简单的算法流程,可以得到种子的数目。

    大致算法分为以下三个步骤:

    1.      将灰度图像二值化,二值化方法可以参考以前的文章,求取像素平均值,灰度直方图都

              可以

    2.      去掉二值化以后的图像中干扰噪声。

    3.      得到种子数目,用彩色标记出来。


    源图像如下:


    程序处理中间结果及最终效果如下:


    二值化处理参见以前的文章 - http://blog.csdn.net/jia20003/article/details/7392325

    大米计数与噪声块消去算法基于连通组件标记算法,源代码如下:

    package com.gloomyfish.rice.analysis;
    
    import java.awt.image.BufferedImage;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.HashMap;
    
    import com.gloomyfish.face.detection.AbstractBufferedImageOp;
    import com.gloomyfish.face.detection.FastConnectedComponentLabelAlg;
    
    public class FindRiceFilter extends AbstractBufferedImageOp {
    	
    	private int sumRice;
    	
    	public int getSumRice() {
    		return this.sumRice;
    	}
    
    	@Override
    	public BufferedImage filter(BufferedImage src, BufferedImage dest) {
    		int width = src.getWidth();
            int height = src.getHeight();
    
            if ( dest == null )
                dest = createCompatibleDestImage( src, null );
    
            int[] inPixels = new int[width*height];
            int[] outPixels = new int[width*height];
            getRGB(src, 0, 0, width, height, inPixels );
            
    		FastConnectedComponentLabelAlg fccAlg = new FastConnectedComponentLabelAlg();
    		fccAlg.setBgColor(0);
    		int[] outData = fccAlg.doLabel(inPixels, width, height);
    		// labels statistic
    		HashMap<Integer, Integer> labelMap = new HashMap<Integer, Integer>();
    		for(int d=0; d<outData.length; d++) {
    			if(outData[d] != 0) {
    				if(labelMap.containsKey(outData[d])) {
    					Integer count = labelMap.get(outData[d]);
    					count+=1;
    					labelMap.put(outData[d], count);
    				} else {
    					labelMap.put(outData[d], 1);
    				}
    			}
    		}
    		
    		// try to find the max connected component
    		Integer[] keys = labelMap.keySet().toArray(new Integer[0]);
    		Arrays.sort(keys);
    		int threshold = 10;
    		ArrayList<Integer> listKeys = new ArrayList<Integer>();
    		for(Integer key : keys) {
    			if(labelMap.get(key) <=threshold){
    				listKeys.add(key);
    			}
    			System.out.println( "Number of " + key + " = " + labelMap.get(key));
    		}
    		sumRice = keys.length - listKeys.size();
    		
            // calculate means of pixel  
            int index = 0;    
            for(int row=0; row<height; row++) {  
                int ta = 0, tr = 0, tg = 0, tb = 0;  
                for(int col=0; col<width; col++) {  
                    index = row * width + col;  
                    ta = (inPixels[index] >> 24) & 0xff;  
                    tr = (inPixels[index] >> 16) & 0xff;  
                    tg = (inPixels[index] >> 8) & 0xff;  
                    tb = inPixels[index] & 0xff;
                    if(outData[index] != 0 && validRice(outData[index], listKeys)) {
                    	tr = tg = tb = 255;
                    } else {
                    	tr = tg = tb = 0;
                    }
                    outPixels[index] = (ta << 24) | (tr << 16) | (tg << 8) | tb;
                }
            }
            setRGB( dest, 0, 0, width, height, outPixels );
            return dest;
    	}
    
    	private boolean validRice(int i, ArrayList<Integer> listKeys) {
    		for(Integer key : listKeys) {
    			if(key == i) {
    				return false;
    			}
    		}
    		return true;
    	}
    
    }
    
    大米着色处理很简单,只是简单RGB固定着色,源码如下:

    package com.gloomyfish.rice.analysis;
    
    import java.awt.image.BufferedImage;
    
    import com.gloomyfish.face.detection.AbstractBufferedImageOp;
    
    public class ColorfulRiceFilter extends AbstractBufferedImageOp {
    
    	@Override
    	public BufferedImage filter(BufferedImage src, BufferedImage dest) {
    		int width = src.getWidth();
            int height = src.getHeight();
    
            if ( dest == null )
                dest = createCompatibleDestImage( src, null );
    
            int[] inPixels = new int[width*height];
            int[] outPixels = new int[width*height];
            getRGB(src, 0, 0, width, height, inPixels );
            
            int index = 0, srcrgb;
            for(int row=0; row<height; row++) {  
                int ta = 255, tr = 0, tg = 0, tb = 0;  
                for(int col=0; col<width; col++) { 
                    index = row * width + col;  
    //                ta = (inPixels[index] >> 24) & 0xff;  
    //                tr = (inPixels[index] >> 16) & 0xff;  
    //                tg = (inPixels[index] >> 8) & 0xff;  
    //                tb = inPixels[index] & 0xff;  
                	srcrgb = inPixels[index] & 0x000000ff;
                	if(srcrgb > 0 && row < 140) {
                		tr = 0;
                		tg = 255;
                		tb = 0;
                	} else if(srcrgb > 0 && row >= 140 && row <=280) {
                		tr = 0;
                		tg = 0;
                		tb = 255;
                	} else if(srcrgb > 0 && row >=280) {
                		tr = 255;
                		tg = 0;
                		tb = 0;
                	}
                	else {
                		tr = tg = tb = 0;
                	}
                	outPixels[index] = (ta << 24) | (tr << 16) | (tg << 8) | tb;
                }
            }
            setRGB( dest, 0, 0, width, height, outPixels );
            return dest;
    	}
    }
    
    测试程序UI代码如下:

    package com.gloomyfish.rice.analysis;
    
    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.FlowLayout;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.Image;
    import java.awt.MediaTracker;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.image.BufferedImage;
    import java.io.File;
    import java.io.IOException;
    
    import javax.imageio.ImageIO;
    import javax.swing.JButton;
    import javax.swing.JComponent;
    import javax.swing.JFileChooser;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    
    public class MainFrame extends JComponent implements ActionListener {
    	/**
    	 * 
    	 */
    	private static final long serialVersionUID = 1518574788794973574L;
    	public final static String BROWSE_CMD = "Browse...";
    	public final static String NOISE_CMD = "Remove Noise";
    	public final static String FUN_CMD = "Colorful Rice";
    	
    	private BufferedImage rawImg;
    	private BufferedImage resultImage;
    	private MediaTracker tracker;
    	private Dimension mySize;
    	
    	// JButtons
    	private JButton browseBtn;
    	private JButton noiseBtn;
    	private JButton colorfulBtn;
    
    	// rice number....
    	private int riceNum = -1;
    	
    	
    	public MainFrame() {
    		JPanel btnPanel = new JPanel();
    		btnPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
    		browseBtn = new JButton("Browse...");
    		noiseBtn = new JButton("Remove Noise");
    		colorfulBtn = new JButton("Colorful Rice");
    		
    		browseBtn.setToolTipText("Please select image file...");
    		noiseBtn.setToolTipText("find connected region and draw red rectangle");
    		colorfulBtn.setToolTipText("Remove the minor noise region pixels...");
    		
    		// buttons
    		btnPanel.add(browseBtn);
    		btnPanel.add(noiseBtn);
    		btnPanel.add(colorfulBtn);
    		
    		// setup listener...
    		browseBtn.addActionListener(this);
    		noiseBtn.addActionListener(this);
    		colorfulBtn.addActionListener(this);
    		
    		browseBtn.setEnabled(true);
    		noiseBtn.setEnabled(true);
    		colorfulBtn.setEnabled(true);
    		
    //		minX = minY =  10000;
    //		maxX = maxY = -1;
    		
    		mySize = new Dimension(500, 300);
    		JFrame demoUI = new JFrame("Rice Detection Demo");
    		demoUI.getContentPane().setLayout(new BorderLayout());
    		demoUI.getContentPane().add(this, BorderLayout.CENTER);
    		demoUI.getContentPane().add(btnPanel, BorderLayout.SOUTH);
    		demoUI.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    		demoUI.pack();
    		demoUI.setVisible(true);
    	}
    	
    	public void paint(Graphics g) {
    		Graphics2D g2 = (Graphics2D) g;
    		if(rawImg != null) {
    			Image scaledImage = rawImg.getScaledInstance(200, 200, Image.SCALE_FAST);
    			g2.drawImage(scaledImage, 0, 0, 200, 200, null);
    		}
    		if(resultImage != null) {
    			Image scaledImage = resultImage.getScaledInstance(200, 200, Image.SCALE_FAST);
    			g2.drawImage(scaledImage, 210, 0, 200, 200, null);
    		}
    		
    		g2.setPaint(Color.RED);
    		if(riceNum > 0) {
    			g2.drawString("Number of Rice : " + riceNum, 100, 300);
    		} else {
    			g2.drawString("Number of Rice : Unknown", 100, 300);
    		}
    	}
    	public Dimension getPreferredSize() {
    		return mySize;
    	}
    	
    	public Dimension getMinimumSize() {
    		return mySize;
    	}
    	
    	public Dimension getMaximumSize() {
    		return mySize;
    	}
    	
    	public static void main(String[] args) {
    		new MainFrame();
    	}
    	
    	@Override
    	public void actionPerformed(ActionEvent e) {
    		if(BROWSE_CMD.equals(e.getActionCommand())) {
    			JFileChooser chooser = new JFileChooser();
    			chooser.showOpenDialog(null);
    			File f = chooser.getSelectedFile();
    			BufferedImage bImage = null;
    			if(f == null) return;
    			try {
    				bImage = ImageIO.read(f);
    				
    			} catch (IOException e1) {
    				e1.printStackTrace();
    			}
    			
    			tracker = new MediaTracker(this);
    			tracker.addImage(bImage, 1);
    			
    			// blocked 10 seconds to load the image data
    			try {
    				if (!tracker.waitForID(1, 10000)) {
    					System.out.println("Load error.");
    					System.exit(1);
    				}// end if
    			} catch (InterruptedException ine) {
    				ine.printStackTrace();
    				System.exit(1);
    			} // end catch
    			BinaryFilter bfilter = new BinaryFilter();
    			rawImg = bfilter.filter(bImage, null);
    			repaint();
    		} else if(NOISE_CMD.equals(e.getActionCommand())) {
    			FindRiceFilter frFilter = new FindRiceFilter();
    			resultImage = frFilter.filter(rawImg, null);
    			riceNum = frFilter.getSumRice();
    			repaint();
    		} else if(FUN_CMD.equals(e.getActionCommand())) {
    			ColorfulRiceFilter cFilter = new ColorfulRiceFilter();
    			resultImage = cFilter.filter(resultImage, null);
    			repaint();
    		} else {
    			// do nothing...
    		}
    		
    	}
    }
    
    关于连通组件标记算法,我实现一个优化过的快速版本,可以参见

    http://blog.csdn.net/jia20003/article/details/7596443



    展开全文
  • 图像处理之应用篇-大米计数

    千次阅读 2012-07-17 23:19:54
    图像处理之应用篇-大米计数续 背景介绍: 请看博客文章《图像处理之简单综合实例(大米计数)》 其实拍出来的照片更多的是含有大米颗粒相互接触,甚至于有点重叠的照片 要准确计算大米的颗粒数非常困难,通过图像...

    图像处理之应用篇-大米计数续

    背景介绍:

    请看博客文章《图像处理之简单综合实例(大米计数)

    其实拍出来的照片更多的是含有大米颗粒相互接触,甚至于有点重叠的照片

    要准确计算大米的颗粒数非常困难,通过图像形态学开闭操作,腐蚀等手

    段尝试以后效果不是很好。最终发现一种简单明了但是有微小误差的计数

    方法。照相机图片:


    算法思想:

    主要是利用连通区域发现算法,发现所有连通区域,使用二分法,截取较小

    部分的连通区域集合,求取平均连通区域面积,根据此平均连通区域面积,

    作为单个大米大小,从而求取出粘连部分的大米颗粒数,完成对整个大米

    数目的统计:

    缺点:

    平均连通区域面积的计算受制于两个因素,一个是最小连通区域集合的选取算法,

    二个样本数量。算法结果跟实际结果有一定的误差,但是误差在1%左右。

     

    程序算法代码详解

    将输入图像转换为黑白二值图像,求得连通区域的算法代码如下:

    src = super.filter(src, null);

    getRGB(src, 0, 0, width,height, inPixels );

    FastConnectedComponentLabelAlgfccAlg = new FastConnectedComponentLabelAlg();

    fccAlg.setBgColor(0);

    int[] outData = fccAlg.doLabel(inPixels, width, height);

     

    获取平均大米颗粒连通区域的代码如下:

    Integer[] values =labelMap.values().toArray(new Integer[0]);

    Arrays.sort(values);

    int minRiceNum = values.length/4;

    float sum = 0;

    for(int v= offset; v<minRiceNum + offset; v++) {

    sum += values[v].intValue();

    }

    float minMeans = sum / (float)minRiceNum;

    System.out.println(" minMeans = " + minMeans);

     

    程序时序图如下:


    程序运行效果如下:


    实际大米颗粒数目为202,正确率为99%

    完成大米数目统计的源代码如下(其它相关代码见以前的图像处理系列文章):

    public class FindRiceFilter extends BinaryFilter {
    	
    	private int sumRice;
    	private int offset = 10;
    	
    	public int getSumRice() {
    		return this.sumRice;
    	}
    	
    	public void setOffset(int pos) {
    		this.offset = pos;
    	}
    
    	@Override
    	public BufferedImage filter(BufferedImage src, BufferedImage dest) {
    		int width = src.getWidth();
            int height = src.getHeight();
            if ( dest == null )
                dest = createCompatibleDestImage( src, null );
    
            int[] inPixels = new int[width*height];
            int[] outPixels = new int[width*height];
            src = super.filter(src, null);
            getRGB(src, 0, 0, width, height, inPixels );
            FastConnectedComponentLabelAlg fccAlg = new FastConnectedComponentLabelAlg();
    		fccAlg.setBgColor(0);
    		int[] outData = fccAlg.doLabel(inPixels, width, height);
    		
    		// labels statistic
    		HashMap<Integer, Integer> labelMap = new HashMap<Integer, Integer>();
    		for(int d=0; d<outData.length; d++) {
    			if(outData[d] != 0) {
    				if(labelMap.containsKey(outData[d])) {
    					Integer count = labelMap.get(outData[d]);
    					count+=1;
    					labelMap.put(outData[d], count);
    				} else {
    					labelMap.put(outData[d], 1);
    				}
    			}
    		}
    		
    		Integer[] values = labelMap.values().toArray(new Integer[0]);
    		Arrays.sort(values);
    		int minRiceNum = values.length/4;
    		float sum = 0;
    		for(int v= offset; v<minRiceNum + offset; v++) {
    			sum += values[v].intValue();
    		}
    		float minMeans = sum / (float)minRiceNum;
    		System.out.println(" minMeans = " + minMeans);
    		
    		// try to find the max connected component
    		Integer[] keys = labelMap.keySet().toArray(new Integer[0]);
    		Arrays.sort(keys);
    		int threshold = 10;
    		ArrayList<Integer> listKeys = new ArrayList<Integer>();
    		for(Integer key : keys) {
    			if(labelMap.get(key) <=threshold){
    				listKeys.add(key);
    			} else {
    				float xx = labelMap.get(key);
    				float intPart = (float)Math.floor(xx / minMeans + 0.5f);
    				sumRice += intPart;
    			}
    		}
    		System.out.println( "Number of rice  = " + sumRice);
    		// sumRice = keys.length - listKeys.size();
    		
            // calculate means of pixel  
            int index = 0;    
            for(int row=0; row<height; row++) {  
                int ta = 0, tr = 0, tg = 0, tb = 0;  
                for(int col=0; col<width; col++) {  
                    index = row * width + col;  
                    ta = (inPixels[index] >> 24) & 0xff;  
                    tr = (inPixels[index] >> 16) & 0xff;  
                    tg = (inPixels[index] >> 8) & 0xff;  
                    tb = inPixels[index] & 0xff;
                    if(outData[index] != 0 && validRice(outData[index], listKeys)) {
                    	tr = tg = tb = 255;
                    } else {
                    	tr = tg = tb = 0;
                    }
                    outPixels[index] = (ta << 24) | (tr << 16) | (tg << 8) | tb;
                }
            }
            setRGB( dest, 0, 0, width, height, outPixels );
            return dest;
    	}
    
    	private boolean validRice(int i, ArrayList<Integer> listKeys) {
    		for(Integer key : listKeys) {
    			if(key == i) {
    				return false;
    			}
    		}
    		return true;
    	}
    
    }
    
    转载文章请务必注明出处

    展开全文
  • [Matlab][图像处理][圆检测houghcircle]计数运行结果源代码联系作者 运行结果 源代码联系作者 QQ 3538518672
  • 目标: 灰度化--->>>阈值化--->>...轮廓查找计数: 遇到的问题: A. 1.用下面这个自适应阈值必须进行数据的转换,不能直接传入数据!不然程序一直崩溃,找了很久才发现...
  • Matlab编写,用于染色体图像计数,包括反白、去噪、标记、统计等处理
  • 图像处理_对象计数

    2018-11-16 19:56:35
    (1)二值分割 (2)形态学处理 (3)距离变换 (4)连通区域计算
  • 基于数字图像处理的小目标计数(二)

    千次阅读 热门讨论 2018-04-18 00:16:43
    存在接壤现象的细胞计数 因为前面(一)的中的图片每个波点之间间隔较小,这边的细胞图中存在多个目标接壤问题,所以怎样在存在接壤现象的细胞中准确数出个数是这里较前面不同的地方。 解决思路: 进行锐化和...
  • 数字图像处理 染色体计数 Python实现

    千次阅读 2020-02-25 15:04:07
    对于下面这幅图像,编程实现染色体计数,并附简要处理流程说明。 二、实验步骤 1.中值滤波 2.图像二值化 3.膨胀图像 4.腐蚀图像 5.计算光影背景 6.移除背景 7.检测染色体 三、代码 import cv2 import ...
  • 图像分割与计数

    2020-07-29 14:18:17
    本资源压缩包打开后为一个.m文件和一张.jpg图片,实现数字图像处理中的二值化;直方图;腐蚀与膨胀;图形计数等功能
  • 本实验为使用MATLAB编写的细胞图像分割及计数系统,实现了对图像内细胞的计数,以及对每个细胞周长和面积的测量,并分别展示了分割后的每个细胞的图像。 实验步骤共分为图像预处理、图像预分割、空洞填充、黏连细胞...
  • 对于下面这幅图像,编程实现染色体计数,并附简要处理流程说明。 处理步骤: 1. 读取图像,转换为灰度图像 平滑滤波去噪 图像二值化 对图像进行膨胀 再次膨胀(视情况而定) 腐蚀(视情况而定) 反转 统计连通...
  • 一位网友给我发了几张灰度图像,说是他们单位的工业相机拍摄的,画质非常的清楚,他们单位是农业科研单位,特别想知道种子的数量,他想知道的是每次工业相机拍摄种子图片中有多少颗粒种子,想到了用图像处理的办法...
  • HALCON图像处理的粘连零件颗粒计数

    千次阅读 2016-12-12 21:37:25
    基于HALCON图像处理的粘连零件颗粒计数方法研究 测试使用图片dev_clear_window() *读取图片 read_image (Image, 'C:/Users/Administrator/Desktop/new/QQ图片20161212193015.jpg') get_image_size (Image, Width, ...
  • 基于图像处理的目标数量的自动计数方法可以对采集到的图像进行处理来实现自动计数,也可以先用采集到的图像减去背景图像从而得到一个差值图像,然后对差值图像进行处理实现计数。无论哪种方式,都需要首先进行目标和...
  • 笔记:在下面图像中的圆,有相对于图像背景色来说更暗的圆,也有相对于图像背景色来说更亮的圆,所以通过两次画轮廓的方式,先画出图像上相对于背景色更亮的圆的轮廓,再画出图像上相对于背景色更暗的圆的轮廓,并...
  • 图像处理-人脸识别

    千次阅读 2019-07-19 09:59:40
    本篇文章主要包含了关于人脸相关的知识。
  • 以前没有关注这方面的内容,因为...所以就想着从图像处理的角度去尝试下,网上也已经有一些相关的利用MATLAB编写的代码。 一般来说利用图像处理的手段可以分为以下几个步骤: 图像格式的转换,及RGB图像转化为GRAY...
  • 该文档详细介绍了基于数字图像处理的骨髓细胞计数方法,通过比较多种方法来获得最佳解决途径,对我们认识数字图像处理以及MATLAB基本使用方法有很大帮助
1 2 3 4 5 ... 20
收藏数 25,734
精华内容 10,293
关键字:

图像处理 计数