[Capítulo práctico: Segmentación de objetos adhesivos: uso de la segmentación geométrica para realizar la detección de segmentación de monedas]

Capítulo práctico: Segmentación de objetos adhesivos: uso de detección de esquinas, determinación del área de ROI, transformación de perspectiva y segmentación geométrica para lograr la segmentación y el conteo de monedas

1. Antecedentes

    Compartí un artículo antes, que utiliza el método de segmentación geométrica para realizar la segmentación y detección de tapas de botellas . Este artículo utiliza principalmente el algoritmo de este artículo y lo aplica a la detección de monedas (porque la resolución de la imagen es algo diferente y la calidad También es un poco diferente y requiere un pequeño ajuste de parámetros). Después de un pequeño ajuste de parámetros, aquí está el código que se puede ejecutar directamente.

Figura 1 Efecto de detección de tapas de botellas
Figura 2 Detección de monedas

2.Ideas

一、基于****Harrs****的角点检测
Habrá áreas cóncavas y convexas entre objetos adhesivos circulares. La detección de puntos de esquina o la detección de puntos cóncavos y convexos se puede realizar en las áreas conectadas. Si los puntos de detección están completos determina la precisión de la segmentación. Para garantizar el efecto de segmentación, la etapa de detección de esquinas puede detectar más puntos de esquina. Encuentre la distancia euclidiana mínima al punto más cercano de todos los puntos calculando la media y la mediana de las distancias. El indicador medio es adecuado para situaciones en las que hay muchos puntos de ruido y grandes distancias. Para situaciones donde hay muchos puntos de ruido y grandes distancias. Parte del ruido se puede eliminar mediante el indicador medio o el indicador mediano. Para filtrar aún más algunos puntos de ruido y juzgar mejor si los dos puntos son partes conectadas del objeto, debido a que las dos esquinas de las partes conectadas se giran 90 ° para obtener un área de ROI positiva, suponiendo que el área de ROI es La conectada La pieza tiene una mayor tasa de llenado en el área ROI. Por lo tanto, esta función se utiliza para el muestreo de ROI. De estos, sólo el ROI cuadrado proporciona una mejor medida de su tasa de cumplimiento. Al calcular las coordenadas de la imagen, es necesario realizar una transformación de coordenadas para mover el origen de las coordenadas al centro de la imagen. Después de obtener dos puntos de esquina, mediante la transformación de coordenadas y la adquisición de la matriz de rotación, cualquier punto de la imagen se puede girar un cierto ángulo alrededor de un punto. Debido a que es necesario calcular la tasa de llenado, se requiere una transformación de perspectiva para encontrar la relación entre el área del contorno del ROI y el área del ROI. Debido a que los ángulos de los diferentes cuadriláteros son diferentes, es necesario ordenar todos los puntos. Al mismo tiempo, se requiere un método especial. El caso es que si la diagonal del cuadrilátero es vertical y recta, no es necesario ordenar, de lo contrario se producirán errores de corrección. Calcule la relación entre el área del contorno binarizado y el área del ROI a través del ROI muestreado, obtenga la tasa de llenado y establezca un valor. Si es mayor que el umbral, se realiza la segmentación.
二、均值去噪点

三、ROI取样

四、坐标变换

五、旋转矩阵获取

六、透视变换

七、填充率计算

3. Código

    将下面代码放在.py文件当中,读取图片,运行之后,便会在当前路径自动创建文件夹将所有图片保存里面。

"""
作者:冯耿鑫
时间:2021/1/9
功能:对相连的圆形物体进行分割
思路:
    =>>创新:形态学操作的小技巧可以定义一个卷积核、然后在本卷积核上画圆,就是一个圆形的卷积了
    =>>基于Harris角点检测、得出dist图像,因为再拐角处会有很多个角点,为了只求一个,所以进行二值化,膨胀,求拐点的形心。
    =>>对角点进行x方向的排序
    =>>进行坐标变换、以及旋转矩阵求出垂直的另一条直线
    =>>进行透视变换,矫正ROI区域,需要通过透视变换来求得,其中ROI的透视变换用到了坐标排序,其中需要注意一种对角线竖直的情况,然后求包含物体的饱和率,从而进行筛选。
    =>>利用连通域进行颜色显示
"""

# -*- coding:utf-8 -*-
import cv2 as cv
import numpy as np
import cv2
import math
import os
# 创建文件进行图片保存
def make_dir_save_img(path,img, binary,open,color,result ):
    if not os.path.exists(name):  # 判断是否存在
        os.makedirs( name)  # 不存在就创建文件夹
    if not os.path.exists("roi\\"+name):  # 判断是否存在
        os.makedirs("roi\\" +name)  # 不存在就创建文件夹

    cv.imwrite(name+"\\img.png",img)
    cv.imwrite(name+"\\binary.png",binary)
    cv.imwrite(name+"\\open.png",open)
    cv.imwrite(name+"\\color.png",color)
    cv.imwrite(name+"\\result.png",result)


class SegmentationConnectObject(object):
    def __init__(self,img,binary):
        self.img = img          # 原图
        self.binary = binary    # 二值化图片
        self.number = 0         # 第几个轮廓
        self.answer = False     # 一开始默认是不是相连的
        self.H,self.W,self.C = img.shape

    # 寻找距离最小的两个点
    def main_find_mindist_points(self):
        """
        :function: 用来寻找两个最近的点,用来进行区域分析
        :return:
        """

        """=>>圆形卷积核进行形态学操作,消除杂点噪声、以及光滑变换<<="""
        k2 = np.zeros((6, 6), np.uint8)                           # <==定义一个卷24x24的卷积核
        cv2.circle(k2, (3, 3), 3, (1, 1, 1), -1, cv2.LINE_AA)    # <==在这个卷积核上进行画一个鹃形的卷积核
        k1 = cv.getStructuringElement(cv.MORPH_ELLIPSE,(3,3))
        self.binary= cv.morphologyEx(self.binary, cv.MORPH_DILATE, k1)     # 进行开操作,也就是先腐蚀后膨胀

        open = cv.morphologyEx(self.binary, cv.MORPH_OPEN, k2)     # 进行开操作,也就是先腐蚀后膨胀


        """=>>利用Harris进行角点检测<<= """
        harris = cv2.cornerHarris(open, 2, 5, 0.04)     #<== 进行角点检测,blockSize:角点检测中要考虑的领域大小||ksize - Sobel:求导中使用的窗口大小||k - Harris:角点检测方程中的自由参数, 取值参数为[0, 04, 0.06]
        harris = cv2.dilate(harris, None)               # 对角点进行一个简单的膨胀、不然的话轮廓会不好寻找
        # img[harris > 0.2 * harris.max()] = [0, 0, 255]  #<== 通过角点检测之后只有边缘像素是有值的,拐角的地方是比较大,所以利用这个条件进行显示
        pix_max = 0.2 * harris.max()                      # <==获取选择角点的阈值
        ret, binary_p = cv.threshold(harris, pix_max, 255, cv.THRESH_BINARY)  # 因为选择出来的像素太多了,又类似与轮廓,所以我们直接进行阈值分割发现轮廓
        binary_p = np.uint8(binary_p)                    # 二值化前需要对位数进行转换
        contours = cv2.findContours(binary_p, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)[0]  # 发现角点的轮廓,用来发现其角点的质心


        """=>>找到所有的可能坐标点<<= """
        points = []             # 用来储存所有的角点坐标
        for c in contours:      # 横向
            # 获取矩形框的四个参数
            mm = cv.moments(c)  # 几何重心的获取
            cx, cy = int(mm['m10'] / mm['m00']), int(mm['m01'] / mm['m00'])
            points.append((int(cx), int(cy)))  # 将坐标保留在points列表中
            cv.circle(self.img, (int(cx), int(cy)), 3, (0, 0, 255), -1)


        """=>>对所有的角点排序,方向为x从小到大<<= """
        points_sorted_x = self.sort_x(points)
        # for i, p in enumerate(points_sorted_x):
            # cv.circle(self.img, p, 4, (255, 0, 0), -1)  # 画出点
            # cv.putText(self.img,str(i) , p, cv.FONT_HERSHEY_SIMPLEX, 0.5, (0, 100, 255), 2)


        """=>>因为有很多角点,如何获得最小相连的两个点呢,通过遍历所有点,获取最小距离用来求平均值,用来作为指标作为阈值,筛选太远的点<<= """
        points_sorted_x_2 = points_sorted_x.copy()          # 因为要遍历两次,所以赋值一份方便后面更改
        distance_1 = []                                     # 所有点都进行遍历、储存每个点相连做近的点
        for p1 in points_sorted_x:                  # p1作为父点
            x1, y1 = p1                             # p1的坐标
            distance_2 = []                         # 用来储存所有子点p2到p1的距离,然后获取最小距离给diatance_1
            for p2 in points_sorted_x_2:            # p2作为父点
                x2, y2 = p2                         # p2的坐标
                if x1 == x2 and y1 == y2:           # 因为两个列表是一样的,所以会有遇到相同的点,需要跳过,不然distance_2中最小的都是0
                    continue                        # 循环到原来的带点就不进行计算
                else:
                    l = pow(abs(x1 - x2) ** 2 + abs(y1 - y2) ** 2, 0.5)  # 计算父点与子点的欧式距离
                    distance_2.append(l)            # 将所有欧式距离保存在distance_2中
            distance_1.append(min(distance_2))      # 获取每个父点到子点的最小欧式距离
        mean_dist = np.mean(distance_1)             # 这里设置了两个指标,一个是平均值,适合密集点
        median_dist = np.median(distance_1)         # 一个是中间数,适合杂点较少情况



        """=>>上面根据模型求出距离指标,下面将通过设定阈值进行求解<<= """
        choose = []                                 # choose列表使用来记录已经检测完毕的两个点,用来判断,如果没有检测成功,就继续检测,如果检测成功,那就跳过避免重复检测
        for number, p1 in enumerate(points_sorted_x):   # 遍历父点
            x1, y1 = p1                                # 父点坐标
            for p2 in points_sorted_x:                  # 遍历子点
                x2, y2 = p2                             # 子点坐标
                if x1 == x2 and y1 == y2:               # 过滤相同的点
                    continue
                else:                                   # 求欧式距离
                    l = pow(abs(x1 - x2) ** 2 + abs(y1 - y2) ** 2, 0.5)
                if l > mean_dist * 0.3 and l < mean_dist * 1.8:     #<<== 设定约束条件,如果在这个阈值范围就可以进行后续的分割功能
                    if p1 in choose or p2 in choose:                # 如果点在choose中就代表这两个点已经检测成功
                        continue
                    self.check_connect(x1, y1, x2, y2)  #<<==判断是否连接函数
                    if self.answer:                          # 当分割成功的时候,用来记录p1,p2这两个点
                        choose.append(p1)
                        choose.append(p2)
                        self.answer = False  # 需要重新赋值,不然边True之后就会一直默认正确
        color,result = self.connect_domain()
        return self.img,self.binary, open,color,result
    # 冒泡排序对角点坐标进行排序
    def sort_x(self,points):
        """
        function:冒泡排序算法实现对x方向进行排序
        """
        l = len(points)
        for i in range(l - 1):
            for j in range(l - 1 - i):
                # if points[j][1]>points[j+1][1]:
                #     temp = points[j]
                #     points[j] = points[j+1]
                #     points[j+1] = temp
                if points[j][0] > points[j + 1][0]:
                    temp = points[j]
                    points[j] = points[j + 1]
                    points[j + 1] = temp
        return points

    # 通过旋转矩阵,实现任一点的旋转
    def rota(self,x1, y1, x2, y2):

        """
        :function:以任意点为中线,通过坐标平移,然后通过旋转,再平移回来,最终完成旋转。
        :return:
        """

        # 获取直线的中点
        cx, cy = (x1 + x2) / 2, (y1 + y2) / 2
        # 偏移矩阵
        C = np.array([[cx], [cy]])
        # 旋转角度
        degree = math.radians(90)
        # 旋转矩阵
        A = np.array([[math.cos(degree), -math.sin(degree)],
                      [math.sin(degree), math.cos(degree)]])
        # 输入坐标
        X1 = np.array([[x1], [y1]])
        X2 = np.array([[x2], [y2]])
        # 进行偏移,将中间点转换为中间坐标
        X1 = X1 - C
        X2 = X2 - C
        # 利用矩阵的乘积求出旋转坐标
        Y1 = np.dot(A, X1)
        Y2 = np.dot(A, X2)
        # 转换绝对坐标的形式
        Y1 = Y1 + C
        Y2 = Y2 + C

        out_x1, out_y1, out_x2, out_y2 = int(Y1.ravel()[0]), int(Y1.ravel()[1]), int(Y2.ravel()[0]), int(Y2.ravel()[1])

        return out_x1, out_y1, out_x2, out_y2

    # 检查是否为相连物体
    def check_connect(self,x1, y1, x2, y2):
        """
        :function:检查这两个点是否为相连接的两个点
        """

        """==>>因为后面需要用到图像坐标的各种运算,所以需要先进行坐标变换<<=="""
        x1, y1 = self.change_coordinate_lt_center(x1, y1)   # 将第一个点也就是父点转换为笛卡尔坐标系
        x2, y2 = self.change_coordinate_lt_center(x2, y2)   # 将第二个点也就是子点转换为笛卡尔坐标系


        """==>>进行旋转90°,分别获得父、子的旋转坐标<<=="""
        x3, y3, x4, y4 = self.rota(x1, y1, x2, y2)       #x3,y3是父点的逆时针旋转点、x4,y4是子点的旋转坐标点


        """==>>转为图像坐标系<<=="""
        x1, y1 = self.change_coordinate_center_lt(x1, y1)   # 将父点坐标转为图像坐标
        x2, y2 = self.change_coordinate_center_lt(x2, y2)   # 将子点坐标转为图像坐标
        x3, y3 = self.change_coordinate_center_lt(x3, y3)   # 将父点坐标旋转坐标转为图像坐标
        x4, y4 = self.change_coordinate_center_lt(x4, y4)   # 将子点坐标旋转坐标转为图像坐标

        """==>>进行透视变换、因为是倾斜的矩形,必须透视变换,不然的话没办法求比例<<=="""
        pts = [(x1, y1), (x3, y3), (x2, y2), (x4, y4)]

        """==>>进行透视变换、因为是倾斜的矩形,必须透视变换,不然的话没办法求比例<<=="""
        self.Perspective_transformation(pts)

        """==>>answer表示的是,检测区域为相连接部分,<<=="""
        if self.answer:
            arrPt = np.array(pts, np.int32).reshape((-1, 1, 2))  # 将坐标转换为n行两列的形式
            cv.polylines(img, [arrPt], True, (255, 0, 255), 1)

    # 图片坐标系转为笛卡尔坐标系
    def change_coordinate_lt_center(self,x_in, y_in):
        """
        x_out = x_in-1/2W
        y_out = -(y_in-1/2H) = 1/2H-y_in
        """
        x_out = x_in - 1 / 2 * self.W
        y_out = 1 / 2 * self.H - y_in
        return x_out, y_out

    # 笛卡尔坐标系转为图片的坐标系
    def change_coordinate_center_lt(self,x_in, y_in):
        """

        x_out = x_in+1/2W
        y_out = -(y_in-1/2H) = 1/2H-y_in =>>y_in = 1/2H-y_out ==>> y_out = 1/2H-yin
        """
        x_out = x_in + 1 / 2 * self.W
        y_out = 1 / 2 * self.H - y_in
        return int(x_out), int(y_out)

    def order_points(self,pts):
        # initialzie a list of coordinates that will be ordered
        # such that the first entry in the list is the top-left,
        # the second entry is the top-right, the third is the
        # bottom-right, and the fourth is the bottom-left
        rect = np.zeros((4, 2), dtype="float32")

        # the top-left point will have the smallest sum, whereas
        # the bottom-right point will have the largest sum
        s = pts.sum(axis=1)
        rect[0] = pts[np.argmin(s)]
        rect[2] = pts[np.argmax(s)]

        # now, compute the difference between the points, the
        # top-right point will have the smallest difference,
        # whereas the bottom-left will have the largest difference
        diff = np.diff(pts, axis=1)
        rect[1] = pts[np.argmin(diff)]
        rect[3] = pts[np.argmax(diff)]

        # return the ordered coordinates
        return rect
    # 进行透视变换
    def Perspective_transformation(self,pts):

        """==>>获取四个点的坐标,依次是父点、父点旋转点、子点、子点旋转点、同时对对角线竖直的情况进行单独分析<<=="""
        (x1, y1), (x2, y2), (x3, y3), (x4, y4) = pts[0], pts[1], pts[2], pts[3]
        pts1 = np.float32(pts)  # 透视变换前坐标需要转换为32位
        if x1 == x3 or x2 == x4:  # 有一张特殊情况,就是对角线是竖直线,这样的经过排序之后就会出现变形,漏检测,
            rect = pts1
        else:
            rect = self.order_points(pts1)
        (tl, tr, br, bl) = rect

        """==>>计算ROI区域的长宽<<=="""
        widthA = np.sqrt(((br[0] - bl[0]) ** 2) + ((br[1] - bl[1]) ** 2))
        widthB = np.sqrt(((tr[0] - tl[0]) ** 2) + ((tr[1] - tl[1]) ** 2))
        maxWidth = max(int(widthA), int(widthB))
        heightA = np.sqrt(((tr[0] - br[0]) ** 2) + ((tr[1] - br[1]) ** 2))
        heightB = np.sqrt(((tl[0] - bl[0]) ** 2) + ((tl[1] - bl[1]) ** 2))
        maxHeight = max(int(heightA), int(heightB))

        """==>>获取变换后图片的坐标点、获得旋转矩阵、同时进行透视变换<<=="""
        dst = np.array([[0, 0],[maxWidth - 1, 0],[maxWidth - 1, maxHeight - 1],[0, maxHeight - 1]], dtype="float32")     # in the top-left, top-right, bottom-right, and bottom-left
        matrix = cv2.getPerspectiveTransform(rect, dst)     # 获得旋转矩阵
        roi = cv.warpPerspective(self.binary, matrix, (maxHeight, maxWidth))    # 获取roi区域

        """==>>对获取到的目标区域进行面积统计<<=="""
        contours = cv2.findContours(roi, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)[0]  # 发现最外边轮廓
        area_list = []                              #定义一个列表用来储存所有的面积
        for cnt in contours:
            area_list.append(cv.contourArea(cnt))
        if len(area_list) == 0:
            max_cnts = 0                            # 如果区域没有面积,sum会报错,所以需要单独赋值为0
        else:
            max_cnts = sum(area_list)               # 获取面积综合

        area = maxWidth * maxHeight                 # ROI的一个面积
        ratio = max_cnts / area                     # 二值化面积比



        if ratio > 0.8:
            self.number +=1
            cv.circle(self.img, ((x1 + x3) // 2, int(y1 + y3) // 2), 4, (0, 0, 255), -1)
            cv.circle(self.img, (x1, y1), 3, (255, 0, 0), -1)
            cv.circle(self.img, (x2, y2), 3, (255, 0, 0), -1)
            cv.circle(self.img, (x3, y3), 3, (255, 0, 0), -1)
            cv.circle(self.img, (x4, y4), 3, (255, 0, 0), -1)
            cv.line(self.img, (x1, y1), (x2, y2), (0, 255, 255), 1)
            cv.line(self.img, (x3, y3), (x4, y4), (0, 255, 255), 1)
            cv.line(self.binary, (x1, y1), (x3, y3), (0, 0, 0),2)
            cv.putText(self.img, str(self.number), ((x1 + x3) // 2, int(y1 + y3) // 2 - 10), cv.FONT_HERSHEY_SIMPLEX, 0.8,(255, 0, 0), 1)
            roi_img = cv.warpPerspective(self.img, matrix, (maxHeight, maxWidth))
            cv.imwrite(".\\roi\\" +name+"\\"+ str(self.number) + ".png", roi_img)

            self.answer = True

    def connect_domain(self):

        # # 连通域分析
        num_labels, labels, stats, centers = cv2.connectedComponentsWithStats(self.binary, connectivity=8)
        # 利用连通域进行不同轮廓画出不同颜色
        color = np.zeros((self.H, self.W, 3), np.uint8)
        for i in range(1, num_labels):
            mask = labels == i
            color[:, :, 0][mask] = np.random.randint(0, 255)
            color[:, :, 1][mask] = np.random.randint(0, 255)
            color[:, :, 2][mask] = np.random.randint(0, 255)

        result = cv2.addWeighted(img, 0.8, color, 0.5, 0)  # 图像权重叠加
        for i in range(1, len(centers)):
            cv2.drawMarker(result, (int(centers[i][0]), int(centers[i][1])), (255, 0, 0), 1, 10, 2)

        return color,result


def get_binary(img):
    # # 图像预处理
    # # blurred = cv.pyrMeanShiftFiltering(img, 10, 100)  # 边缘保留滤波能够进行去噪是同时有效地保留边缘
    # # gray = cv.cvtColor(blurred, cv.COLOR_BGR2GRAY)  # 进行灰度化为二值化做准备
    # # ret, binary = cv.threshold(gray, thresh=70, maxval=255, type=cv.THRESH_BINARY)  # 固定阈值二值化,将大于thresh得像素点设置为maxval,
    # #
    # blurred = cv.pyrMeanShiftFiltering(img, 5, 50)  # 边缘保留滤波能够进行去噪是同时有效地保留边缘
    #           #获取灰度图
    #
    #
    #
    # # h, s, v = cv.split(hsv)
    # ret, binary = cv.threshold(blurred, 200, 255, cv.THRESH_BINAR)

    blurred = cv.pyrMeanShiftFiltering(img, 5, 80)  # 边缘保留滤波能够进行去噪是同时有效地保留边缘


    gray = cv.cvtColor(blurred, cv.COLOR_BGR2GRAY)  # 进行灰度化为二值化做准备
    ret, binary = cv.threshold(gray, thresh=0, maxval=255, type=cv.THRESH_BINARY|cv.THRESH_OTSU)  # 固定阈值二值化,将大于thresh得像素点设置为maxval,

    # imgHsv = cv.cvtColor(blurred, cv.COLOR_BGR2HSV)              #转换为HSV色彩空间
    # lower = np.array([0, 79, 0])
    # upper = np.array([179, 255, 255])
    # binary = cv2.inRange(imgHsv,lower,upper)                   #获取灰度图

    return  binary



if __name__ == '__main__':

    path = "3.jpg"
    name = os.path.splitext(path)[0]            # 文件名

    img  = cv.imread(path)   # 读取图片

    # 获取二值化图片
    binary = get_binary(img)


    # 创建实例
    seg = SegmentationConnectObject(img,binary)
    # 调用第一个函数开始执行功能,返回二值化、开操作、黑底颜色、结果、原图
    img, binary,open,color,result = seg.main_find_mindist_points()
    # 进行图片保存
    make_dir_save_img(path,img, binary,open,color,result )




    cv.namedWindow("img",0)
    cv.imshow("img",img)
    cv.namedWindow("binary",0)
    cv.imshow("binary",binary)
    cv.namedWindow("open",0)
    cv.imshow("open",open)
    cv.namedWindow("color",0)
    cv.imshow("color",color)
    cv.namedWindow("result",0)
    cv.imshow("result",result)
    cv.waitKey(0)
    cv.destroyAllWindows()

4. Efecto

Figura 3.1 Operación de binarización (la línea divisoria se dibuja arriba)
Figura 3.2 Operación de apertura

Figura 3.3 Extracción de ROI de los puntos de esquina de la posición de adhesión

Figura 3.4 Representaciones de segmentación

Figura 3.5 Diagrama coloreado del análisis de dominio conectado
Figura 3.6 Fusión de imágenes

5. Declaración

El contenido compartido esta vez se basa principalmente en el ajuste de parámetros del proyecto anterior de segmentación de tapas de botellas. En la aplicación del reconocimiento de monedas, todavía quedan muchas áreas que necesitan ser optimizadas en el código y algoritmo. Puedes dejar tus valiosas opiniones en el área de comentarios y permítanos discutir el progreso juntos. Gracias a todos. ¡Apoyo! ! !

6. Otros artículos


1.理论系列:

Capítulo 1: Resumen de pycharm, anaconda, opencv, pytorch, tensorflow, paddlex y otras configuraciones del entorno [versión py de procesamiento de imágenes] Capítulo 2:

Introducción básica y aplicación del algoritmo OpenCv

Capítulo 3: Operaciones y conceptos básicos de lectura y escritura de imágenes y videos de OpenCv Aplicación

Capítulo 4: Resumen de la segmentación/binarización del umbral de OpenCv (imágenes de un solo canal y multicanal)


2.项目系列:

Proyecto 1: Sistema de reescritura de grados 4 y 6
Proyecto 2: Parte práctica: Segmentación de objetos adhesivos: uso de la segmentación geométrica para realizar la segmentación y detección de tapas de botellas
==》Proyecto 3: Parte práctica: Segmentación de objetos adhesivos: uso de la segmentación geométrica para realizar la segmentación de monedas y Proyecto de detección
cuatro: combate práctico: segmentación de objetos adhesivos: uso de la segmentación geométrica para realizar la segmentación y detección de células
Proyecto cinco: combate práctico: segmentación de objetos adhesivos: uso del algoritmo de cuenca para realizar la segmentación y detección de granos de azúcar

Supongo que te gusta

Origin blog.csdn.net/DGWY161744/article/details/129938297
Recomendado
Clasificación