数字图像处理课程作业1-大米检测

写在最前

这是我大学课程的数字图像处理的实验报告,代码大部分是从网上直接复制使用,小部分是我自己改写的(例如matplotlib的使用),可以直接运行。内容比较详细,但是希望大家能够先理解一下思路再使用,学习图像处理的思路最重要。

1.实验目的:

综合利用滤波、分割、图像分割、特征描述等知识,实现大米实际尺度、整精米的检测

2.实验要求:

检测出图中的碎米,并在相应的米粒上打上标志。

数字图像处理课程作业1-大米检测_第1张图片

3.实验分析:

①米粒与背景对比不明显,需要用一个阈值对其进行二值化

②背景存在噪声需要对其进行去噪声

③找到对应的米粒需要对其进行轮廓检测

④找到其中的碎米需要对其进行面积阈值处理,找出面积小的碎米

流程图如下

在这里插入图片描述

4.核心处理图像函数分析:

4.1 自适应阈值

def adaptiveThreshold(src, maxValue, adaptiveMethod, thresholdType, blockSize, C, dst=None):

自适应阈值法(adaptiveThreshold),它的思想不是计算全局图像的阈值,而是根据图像不同区域亮度分布,计算其局部阈值,所以对于图像不同区域,能够自适应计算不同的阈值,因此被称为自适应阈值法。(其实就是局部阈值法)

参数说明:

  • src: InputArray类型的src,输入图像,填单通道,单8位浮点类型Mat即可
  • maxValue: 预设满足条件的最大值
  • adaptiveMethod: 指定自适应阈值算法。可选择ADAPTIVE_THRESH_MEAN_C 或 ADAPTIVE_THRESH_GAUSSIAN_C两种
  • thresholdType: 指定阈值类型。可选择THRESH_BINARY或者THRESH_BINARY_INV两种。(即二进制阈值或反二进制阈值
  • blockSize: 表示邻域块大小,用来计算区域阈值,一般选择为3、5、7…等

作用: 因地制宜的二值化处理

4.2 形态学变化

def getStructuringElement(shape, ksize, anchor=None):

参数说明:

  • shape:模板形状
  • ksize:模板大小
def morphologyEx(src, op, kernel, dst=None, anchor=None, iterations=None, borderType=None, borderValue=None):

参数说明:

  • src传入的图片
  • op进行变化的方式
  • kernel表示方框的大小

对图像进行一系列的膨胀腐蚀组合

作用:

腐蚀:删除对象边界的某些像素
膨胀:给图像中的对象边界添加像素

4.3 轮廓检测

def findContours(image, mode, method, contours=None, hierarchy=None, offset=None):

参数说明:

  • image:单通道图像矩阵,可以是灰度图,但更常用的是二值图像,一般是经过Canny、拉普拉斯等边 缘检测算子处理过的二值图像

  • mode:定义轮廓的检索模式,

  • method:定义轮廓的近似方法

作用: 检测出米粒的轮廓

4.4 绘制椭圆拟合曲线

def fitEllipse(points):

参数说明:

  • points: 一个二维点集

作用: 实现椭圆的拟合

def ellipse(img, center, axes, angle, startAngle, endAngle, color, thickness=None, lineType=None, shift=None):

参数说明:

  • img: 图像
  • center:圆心坐标
  • axes:轴的长度
  • angle:偏转角度
  • start_angle:圆弧起始角的角度
  • end_angle:圆弧终结角的角度
  • color:线条的颜色

作用:椭圆的轮廓绘制

5.实际图像处理代码分析

5.1 二值化处理

cv2.adaptiveThreshold(gray,255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY,103, 1)

adaptiveThreshold这个函数我们采用的是ADAPTIVE_THRESH_MEAN_C为领域内均值,THRESH_BINARY黑白二值化

图1为二值化处理后的图像,可以看到虽然整体已经二值化成功但是,还是有一些白点噪声,因此我们还需要进行开运算去噪

数字图像处理课程作业1-大米检测_第2张图片

5.2 开运算处理

 element = cv2.getStructuringElement(cv2.MORPH_CROSS,(3, 3))
 dst = cv2.morphologyEx(dst,cv2.MORPH_OPEN ,element)  #开运算去噪

先腐蚀后膨胀的过程称为开运算。用来消除小物体、在纤细点处分离物体、平滑较大物体的边界的同时并不明显改变其面积。我们利用3*3的十字形模板对其进行开运算处理去除噪声,得到下图,可以看到相比起二值化的图像,开运算处理后的图像噪声点明显减少了很多,可以为我们接下来绘制轮廓奠定基础。
数字图像处理课程作业1-大米检测_第3张图片
数字图像处理课程作业1-大米检测_第4张图片

5.3 绘制轮廓

contours, hierarchy = cv2.findContours(dst,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)  #轮廓检测函数

代码中用的是CV_RETR_EXTERNAL,只检测最外围轮廓,包含在外围轮廓内的内围,CV_CHAIN_APPROX_SIMPLE 仅保存轮廓的拐点信息,把所有轮廓拐点处的点保存入contours,所有米粒轮廓图如图3

5.4 椭圆描边

def find_rices(contours):
    count=0 #米粒总数
    ares_avrg=0  #米粒平均
    #遍历找到的所有米粒
    # print(contours)
    for cont in contours:
        # 用于计算图像轮廓的面积。
        ares = cv2.contourArea(cont)
        print(ares)

        if ares < 5:
            continue

        # ares_avrg += ares
        if 100<ares<430:
            count += 1
            #  当得到对象轮廓后,可用boundingRect()得到包覆此轮廓的最小正矩形
            rect = cv2.boundingRect(cont)

            # 绘制椭圆拟合曲线
            ellipse = cv2.fitEllipse(cont)
            # 绘制椭圆圆弧
            cv2.ellipse(img, ellipse,(0xff),2)
            y = 10 if rect[1] < 10 else rect[1]
            cv2.putText(img, str(count), (rect[0], y), cv2.FONT_HERSHEY_COMPLEX, 0.5, (247, 247, 25), 1)
    return  count

得到轮廓列表后,对其中的轮廓面积值进行判断,找到面积小的碎米,如下图3

数字图像处理课程作业1-大米检测_第5张图片

6.完整代码和图像对比

6.1 完整代码

import cv2  #导入opencv模块
import matplotlib.pyplot as plt
from matplotlib import font_manager
font  = font_manager.FontProperties(fname=r".\OPPOSans-H.ttf")

def origin_image_handle(img):
    # 转换为灰度图
    gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    # 使用局部阈值的大津算法进行图像二值化
    dst = cv2.adaptiveThreshold(gray,255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY,103, 1)
    # cv2.imshow('111',dst)
    # 返回一个十字形的Mat型矩阵。
    element = cv2.getStructuringElement(cv2.MORPH_CROSS,(3, 3))
    dst=cv2.morphologyEx(dst,cv2.MORPH_OPEN ,element)  #开运算去噪
    cv2.imshow('2222',dst)
    contours, hierarchy = cv2.findContours(dst,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)  #轮廓检测函数

    return dst,contours

def find_rices(contours):
    count=0 #米粒总数
    ares_avrg=0  #米粒平均
    #遍历找到的所有米粒
    # print(contours)
    for cont in contours:
        # 用于计算图像轮廓的面积。
        ares = cv2.contourArea(cont)
        print(ares)

        if ares < 5:
            continue

        # ares_avrg += ares
        if 100<ares<430:
            count += 1
            #  当得到对象轮廓后,可用boundingRect()得到包覆此轮廓的最小正矩形
            rect = cv2.boundingRect(cont)

            # 绘制椭圆拟合曲线
            ellipse = cv2.fitEllipse(cont)
            # 绘制椭圆圆弧
            cv2.ellipse(img, ellipse,(0xff),2)
            y = 10 if rect[1] < 10 else rect[1]
            cv2.putText(img, str(count), (rect[0], y), cv2.FONT_HERSHEY_COMPLEX, 0.5, (247, 247, 25), 1)
        # count += 1
        # #  当得到对象轮廓后,可用boundingRect()得到包覆此轮廓的最小正矩形
        # rect = cv2.boundingRect(cont)
        #
        # # 绘制椭圆拟合曲线
        # ellipse = cv2.fitEllipse(cont)
        # # 绘制椭圆圆弧
        # cv2.ellipse(img, ellipse, (0xff), 2)
        # y = 10 if rect[1] < 10 else rect[1]
        # cv2.putText(img, str(count), (rect[0], y), cv2.FONT_HERSHEY_COMPLEX, 0.5, (247, 247, 25), 1)
    return  count

if __name__ == '__main__':
    img = cv2.imread("img.png")
    # 打开一个新的窗口
    plt.figure()
    plt.subplot(1, 3, 1,)
    plt.title('原始图像',fontproperties = font)
    # 显示原始图像
    plt.imshow(img)

    dst, contours= origin_image_handle(img)
    plt.subplot(1, 3, 2)
    plt.title('二值化图',fontproperties = font)
    # 由于opencv和matplotlib的色彩通道不同,由于OpenCV是以BGR模式加载图像,而matplotlib则是以常见的RGB模式显示图像
    dst1 = cv2.cvtColor(dst, cv2.COLOR_RGB2BGR)

    # 二值化图
    plt.imshow(dst1)

    ### 显示标记图
    count = find_rices(contours)
    plt.subplot(1,3,3)
    plt.title('标记图',fontproperties = font)
    plt.text(s='估计有{}颗碎粒'.format(count), x=130, y=500, fontproperties=font)
    plt.imshow(img)
    cv2.imshow('121212',img)

    plt.show()

    cv2.waitKey()

6.2 图像对比图

如图5为原始图像,二值化开运算处理图像,碎米标记图的三个对比图,可以估计到碎米的数量为18颗

数字图像处理课程作业1-大米检测_第6张图片

7. 实验感想

这次实验相比起之前的实验所涉及的图像处理方法丰富了许多,首先利用的到了图像分割的技术,阈值处理,也利用到了滤波对图像的噪声进行滤除,最后通过特征描述找到米粒的轮廓,并且利用米粒的大小进行碎米选择,描绘出轮廓。其中我也遇到了许多的问题,例如碎米阈值的选择,开运算中模板算子的选择,在尝试许多次后才找到最优解

写在最后

如果觉得写的不错的小伙伴记得给个赞哦!欢迎评论与我交流!

你可能感兴趣的:(大学课程笔记,计算机视觉,算法,图像处理)