国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【實(shí)戰(zhàn)篇:粘連物體分割——利用幾何分割實(shí)現(xiàn)瓶蓋分割檢測】

這篇具有很好參考價(jià)值的文章主要介紹了【實(shí)戰(zhàn)篇:粘連物體分割——利用幾何分割實(shí)現(xiàn)瓶蓋分割檢測】。希望對大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

一、背景

????在去年學(xué)習(xí)opencv的過程當(dāng)中,做過一張瓶蓋分割的練習(xí)。目的就是為了分割出每個(gè)瓶蓋,當(dāng)時(shí)想著,除了霍夫圓檢測思路之外,能不能根據(jù)相連瓶蓋的特征進(jìn)行分割呢?于是便想到了根據(jù)角點(diǎn)檢測其相連位置,然后在相連位置之間畫一根線進(jìn)行切除。是不是想法很單純,覺得很好實(shí)現(xiàn)?其實(shí)實(shí)現(xiàn)過程中遇到不少問題,檢測的角點(diǎn)很多,如何過濾掉剩下粘連處的角點(diǎn)?那么多個(gè)角點(diǎn),如何保證點(diǎn)跟另一個(gè)點(diǎn)剛好是相連位置的兩個(gè)點(diǎn)?下面附上代碼的整體實(shí)現(xiàn)思路,本次文章制作簡單的分享,后續(xù)有時(shí)間會更新,逐步簡潔實(shí)現(xiàn)流程以及原理。

opencv粘連分割,計(jì)算機(jī)視覺,opencv,人工智能,目標(biāo)檢測,圖像處理

二、思路

一、基于****Harrs****的角點(diǎn)檢測
圓形相粘物體之間會存在凹凸區(qū)域、可以通過對相連區(qū)域進(jìn)行角點(diǎn)檢測、或者凹凸點(diǎn)檢測。檢測點(diǎn)是否齊全決定分割的準(zhǔn)確度。為了保證分割效果,角點(diǎn)檢測階段經(jīng)可能檢測多一些角點(diǎn)。
二、均值去噪點(diǎn)
對所有點(diǎn)求最近點(diǎn)求最小歐式距離,通過對距離進(jìn)行求均值以及中位數(shù)。其中均值指標(biāo)適用于雜點(diǎn)較多以及距離較大的情況。對于雜點(diǎn)較多,距離較大的情況。通過均值指標(biāo)或者中位數(shù)指標(biāo)能去掉部分雜點(diǎn)。
三、ROI取樣
為了更進(jìn)一步篩選掉部分雜點(diǎn),以及更好第判斷兩點(diǎn)之間是否為物體相連部分,因?yàn)橥ㄟ^相連部分的兩個(gè)角點(diǎn),進(jìn)行旋轉(zhuǎn)90°獲得一個(gè)正方向的ROI區(qū)域,假設(shè)ROI區(qū)域?yàn)橄噙B部分,其ROI區(qū)域中的填充率較大。因此利用本特征進(jìn)行ROI取樣。其中只有正方形ROI才能更好地衡量其填充率。
四、坐標(biāo)變換
在對圖像坐標(biāo)進(jìn)行運(yùn)算的時(shí)候,需要進(jìn)行坐標(biāo)變換,將坐標(biāo)原點(diǎn)移動(dòng)到圖像的中心。
五、旋轉(zhuǎn)矩陣獲取
對獲取到兩個(gè)角點(diǎn),通過坐標(biāo)變換、旋轉(zhuǎn)矩陣的獲取,使圖像中任意點(diǎn)能繞一點(diǎn)進(jìn)行旋轉(zhuǎn)一定角度。
六、透視變換
因?yàn)樾枰?jì)算填充率需要進(jìn)行透視變換,求ROI輪廓面積與ROI面積之比,因?yàn)椴煌倪呅蔚慕嵌炔灰粯?,所以需要對所有點(diǎn)進(jìn)行排序,同時(shí)又一種特殊情況就是四邊形對角線如果是豎直的情況,則不需要及進(jìn)行排序,不然會出現(xiàn)矯正錯(cuò)誤。
七、填充率計(jì)算
通過取樣的ROI進(jìn)行計(jì)算二值化輪廓面積與ROI面積之比,獲取填充率,設(shè)定一個(gè)值,假如大于閾值,就進(jìn)行分割。

三、代碼

????將下面代碼放在.py文件當(dāng)中,讀取圖片,運(yùn)行之后,便會在當(dāng)前路徑自動(dòng)創(chuàng)建文件夾將所有圖片保存里面。

"""
作者:馮耿鑫
時(shí)間:2021/1/9
功能:對相連的圓形物體進(jìn)行分割
思路:
    =>>創(chuàng)新:形態(tài)學(xué)操作的小技巧可以定義一個(gè)卷積核、然后在本卷積核上畫圓,就是一個(gè)圓形的卷積了
    =>>基于Harris角點(diǎn)檢測、得出dist圖像,因?yàn)樵俟战翘帟泻芏鄠€(gè)角點(diǎn),為了只求一個(gè),所以進(jìn)行二值化,膨脹,求拐點(diǎn)的形心。
    =>>對角點(diǎn)進(jìn)行x方向的排序
    =>>進(jìn)行坐標(biāo)變換、以及旋轉(zhuǎn)矩陣求出垂直的另一條直線
    =>>進(jìn)行透視變換,矯正ROI區(qū)域,需要通過透視變換來求得,其中ROI的透視變換用到了坐標(biāo)排序,其中需要注意一種對角線豎直的情況,然后求包含物體的飽和率,從而進(jìn)行篩選。
    =>>利用連通域進(jìn)行顏色顯示
"""

# -*- coding:utf-8 -*-
import cv2 as cv
import numpy as np
import cv2
import math
import os


class SegmentationConnectObject(object):
    def __init__(self,img,binary):
        self.img = img          # 原圖
        self.binary = binary    # 二值化圖片
        self.number = 0         # 第幾個(gè)輪廓
        self.answer = False     # 一開始默認(rèn)是不是相連的
        self.H,self.W,self.C = img.shape

    # 尋找距離最小的兩個(gè)點(diǎn)
    def main_find_mindist_points(self):
        """
        :function: 用來尋找兩個(gè)最近的點(diǎn),用來進(jìn)行區(qū)域分析
        :return:
        """

        """=>>圓形卷積核進(jìn)行形態(tài)學(xué)操作,消除雜點(diǎn)噪聲、以及光滑變換<<="""
        k2 = np.zeros((24, 24), np.uint8)                           # <==定義一個(gè)卷24x24的卷積核
        cv2.circle(k2, (12, 12), 12, (1, 1, 1), -1, cv2.LINE_AA)    # <==在這個(gè)卷積核上進(jìn)行畫一個(gè)鵑形的卷積核
        open = cv.morphologyEx(self.binary, cv.MORPH_OPEN, k2)     # 進(jìn)行開操作,也就是先腐蝕后膨脹


        """=>>利用Harris進(jìn)行角點(diǎn)檢測<<= """
        harris = cv2.cornerHarris(open, 2, 5, 0.04)     #<== 進(jìn)行角點(diǎn)檢測,blockSize:角點(diǎn)檢測中要考慮的領(lǐng)域大小||ksize - Sobel:求導(dǎo)中使用的窗口大小||k - Harris:角點(diǎn)檢測方程中的自由參數(shù), 取值參數(shù)為[0, 04, 0.06]
        harris = cv2.dilate(harris, None)               # 對角點(diǎn)進(jìn)行一個(gè)簡單的膨脹、不然的話輪廓會不好尋找
        # img[harris > 0.2 * harris.max()] = [0, 0, 255]  #<== 通過角點(diǎn)檢測之后只有邊緣像素是有值的,拐角的地方是比較大,所以利用這個(gè)條件進(jìn)行顯示
        pix_max = 0.2 * harris.max()                      # <==獲取選擇角點(diǎn)的閾值
        ret, binary_p = cv.threshold(harris, pix_max, 255, cv.THRESH_BINARY)  # 因?yàn)檫x擇出來的像素太多了,又類似與輪廓,所以我們直接進(jìn)行閾值分割發(fā)現(xiàn)輪廓
        binary_p = np.uint8(binary_p)                    # 二值化前需要對位數(shù)進(jìn)行轉(zhuǎn)換
        contours = cv2.findContours(binary_p, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)[0]  # 發(fā)現(xiàn)角點(diǎn)的輪廓,用來發(fā)現(xiàn)其角點(diǎn)的質(zhì)心


        """=>>找到所有的可能坐標(biāo)點(diǎn)<<= """
        points = []             # 用來儲存所有的角點(diǎn)坐標(biāo)
        for c in contours:      # 橫向
            # 獲取矩形框的四個(gè)參數(shù)
            mm = cv.moments(c)  # 幾何重心的獲取
            cx, cy = int(mm['m10'] / mm['m00']), int(mm['m01'] / mm['m00'])
            points.append((int(cx), int(cy)))  # 將坐標(biāo)保留在points列表中
            cv.circle(self.img, (int(cx), int(cy)), 3, (0, 0, 255), -1)


        """=>>對所有的角點(diǎn)排序,方向?yàn)閤從小到大<<= """
        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)  # 畫出點(diǎn)
            # cv.putText(self.img,str(i) , p, cv.FONT_HERSHEY_SIMPLEX, 0.5, (0, 100, 255), 2)


        """=>>因?yàn)橛泻芏嘟屈c(diǎn),如何獲得最小相連的兩個(gè)點(diǎn)呢,通過遍歷所有點(diǎn),獲取最小距離用來求平均值,用來作為指標(biāo)作為閾值,篩選太遠(yuǎn)的點(diǎn)<<= """
        points_sorted_x_2 = points_sorted_x.copy()          # 因?yàn)橐闅v兩次,所以賦值一份方便后面更改
        distance_1 = []                                     # 所有點(diǎn)都進(jìn)行遍歷、儲存每個(gè)點(diǎn)相連做近的點(diǎn)
        for p1 in points_sorted_x:                  # p1作為父點(diǎn)
            x1, y1 = p1                             # p1的坐標(biāo)
            distance_2 = []                         # 用來儲存所有子點(diǎn)p2到p1的距離,然后獲取最小距離給diatance_1
            for p2 in points_sorted_x_2:            # p2作為父點(diǎn)
                x2, y2 = p2                         # p2的坐標(biāo)
                if x1 == x2 and y1 == y2:           # 因?yàn)閮蓚€(gè)列表是一樣的,所以會有遇到相同的點(diǎn),需要跳過,不然distance_2中最小的都是0
                    continue                        # 循環(huán)到原來的帶點(diǎn)就不進(jìn)行計(jì)算
                else:
                    l = pow(abs(x1 - x2) ** 2 + abs(y1 - y2) ** 2, 0.5)  # 計(jì)算父點(diǎn)與子點(diǎn)的歐式距離
                    distance_2.append(l)            # 將所有歐式距離保存在distance_2中
            distance_1.append(min(distance_2))      # 獲取每個(gè)父點(diǎn)到子點(diǎn)的最小歐式距離
        mean_dist = np.mean(distance_1)             # 這里設(shè)置了兩個(gè)指標(biāo),一個(gè)是平均值,適合密集點(diǎn)
        median_dist = np.median(distance_1)         # 一個(gè)是中間數(shù),適合雜點(diǎn)較少情況



        """=>>上面根據(jù)模型求出距離指標(biāo),下面將通過設(shè)定閾值進(jìn)行求解<<= """
        choose = []                                 # choose列表使用來記錄已經(jīng)檢測完畢的兩個(gè)點(diǎn),用來判斷,如果沒有檢測成功,就繼續(xù)檢測,如果檢測成功,那就跳過避免重復(fù)檢測
        for number, p1 in enumerate(points_sorted_x):   # 遍歷父點(diǎn)
            x1, y1 = p1                                # 父點(diǎn)坐標(biāo)
            for p2 in points_sorted_x:                  # 遍歷子點(diǎn)
                x2, y2 = p2                             # 子點(diǎn)坐標(biāo)
                if x1 == x2 and y1 == y2:               # 過濾相同的點(diǎn)
                    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.6:     #<<== 設(shè)定約束條件,如果在這個(gè)閾值范圍就可以進(jìn)行后續(xù)的分割功能
                    if p1 in choose or p2 in choose:                # 如果點(diǎn)在choose中就代表這兩個(gè)點(diǎn)已經(jīng)檢測成功
                        continue
                    self.check_connect(x1, y1, x2, y2)  #<<==判斷是否連接函數(shù)
                    if self.answer:                          # 當(dāng)分割成功的時(shí)候,用來記錄p1,p2這兩個(gè)點(diǎn)
                        choose.append(p1)
                        choose.append(p2)
                        self.answer = False  # 需要重新賦值,不然邊True之后就會一直默認(rèn)正確
        color,result = self.connect_domain()
        return self.img,self.binary, open,color,result
    # 冒泡排序?qū)屈c(diǎn)坐標(biāo)進(jìn)行排序
    def sort_x(self,points):
        """
        function:冒泡排序算法實(shí)現(xiàn)對x方向進(jìn)行排序
        """
        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

    # 通過旋轉(zhuǎn)矩陣,實(shí)現(xiàn)任一點(diǎn)的旋轉(zhuǎn)
    def rota(self,x1, y1, x2, y2):

        """
        :function:以任意點(diǎn)為中線,通過坐標(biāo)平移,然后通過旋轉(zhuǎn),再平移回來,最終完成旋轉(zhuǎn)。
        :return:
        """

        # 獲取直線的中點(diǎn)
        cx, cy = (x1 + x2) / 2, (y1 + y2) / 2
        # 偏移矩陣
        C = np.array([[cx], [cy]])
        # 旋轉(zhuǎn)角度
        degree = math.radians(90)
        # 旋轉(zhuǎn)矩陣
        A = np.array([[math.cos(degree), -math.sin(degree)],
                      [math.sin(degree), math.cos(degree)]])
        # 輸入坐標(biāo)
        X1 = np.array([[x1], [y1]])
        X2 = np.array([[x2], [y2]])
        # 進(jìn)行偏移,將中間點(diǎn)轉(zhuǎn)換為中間坐標(biāo)
        X1 = X1 - C
        X2 = X2 - C
        # 利用矩陣的乘積求出旋轉(zhuǎn)坐標(biāo)
        Y1 = np.dot(A, X1)
        Y2 = np.dot(A, X2)
        # 轉(zhuǎn)換絕對坐標(biāo)的形式
        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:檢查這兩個(gè)點(diǎn)是否為相連接的兩個(gè)點(diǎn)
        """

        """==>>因?yàn)楹竺嫘枰玫綀D像坐標(biāo)的各種運(yùn)算,所以需要先進(jìn)行坐標(biāo)變換<<=="""
        x1, y1 = self.change_coordinate_lt_center(x1, y1)   # 將第一個(gè)點(diǎn)也就是父點(diǎn)轉(zhuǎn)換為笛卡爾坐標(biāo)系
        x2, y2 = self.change_coordinate_lt_center(x2, y2)   # 將第二個(gè)點(diǎn)也就是子點(diǎn)轉(zhuǎn)換為笛卡爾坐標(biāo)系


        """==>>進(jìn)行旋轉(zhuǎn)90°,分別獲得父、子的旋轉(zhuǎn)坐標(biāo)<<=="""
        x3, y3, x4, y4 = self.rota(x1, y1, x2, y2)       #x3,y3是父點(diǎn)的逆時(shí)針旋轉(zhuǎn)點(diǎn)、x4,y4是子點(diǎn)的旋轉(zhuǎn)坐標(biāo)點(diǎn)


        """==>>轉(zhuǎn)為圖像坐標(biāo)系<<=="""
        x1, y1 = self.change_coordinate_center_lt(x1, y1)   # 將父點(diǎn)坐標(biāo)轉(zhuǎn)為圖像坐標(biāo)
        x2, y2 = self.change_coordinate_center_lt(x2, y2)   # 將子點(diǎn)坐標(biāo)轉(zhuǎn)為圖像坐標(biāo)
        x3, y3 = self.change_coordinate_center_lt(x3, y3)   # 將父點(diǎn)坐標(biāo)旋轉(zhuǎn)坐標(biāo)轉(zhuǎn)為圖像坐標(biāo)
        x4, y4 = self.change_coordinate_center_lt(x4, y4)   # 將子點(diǎn)坐標(biāo)旋轉(zhuǎn)坐標(biāo)轉(zhuǎn)為圖像坐標(biāo)

        """==>>進(jìn)行透視變換、因?yàn)槭莾A斜的矩形,必須透視變換,不然的話沒辦法求比例<<=="""
        pts = [(x1, y1), (x3, y3), (x2, y2), (x4, y4)]

        """==>>進(jìn)行透視變換、因?yàn)槭莾A斜的矩形,必須透視變換,不然的話沒辦法求比例<<=="""
        self.Perspective_transformation(pts)

        """==>>answer表示的是,檢測區(qū)域?yàn)橄噙B接部分,<<=="""
        if self.answer:
            arrPt = np.array(pts, np.int32).reshape((-1, 1, 2))  # 將坐標(biāo)轉(zhuǎn)換為n行兩列的形式
            cv.polylines(img, [arrPt], True, (0, 100, 255), 1)

    # 圖片坐標(biāo)系轉(zhuǎn)為笛卡爾坐標(biāo)系
    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

    # 笛卡爾坐標(biāo)系轉(zhuǎn)為圖片的坐標(biāo)系
    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
    # 進(jìn)行透視變換
    def Perspective_transformation(self,pts):

        """==>>獲取四個(gè)點(diǎn)的坐標(biāo),依次是父點(diǎn)、父點(diǎn)旋轉(zhuǎn)點(diǎn)、子點(diǎn)、子點(diǎn)旋轉(zhuǎn)點(diǎn)、同時(shí)對對角線豎直的情況進(jìn)行單獨(dú)分析<<=="""
        (x1, y1), (x2, y2), (x3, y3), (x4, y4) = pts[0], pts[1], pts[2], pts[3]
        pts1 = np.float32(pts)  # 透視變換前坐標(biāo)需要轉(zhuǎn)換為32位
        if x1 == x3 or x2 == x4:  # 有一張?zhí)厥馇闆r,就是對角線是豎直線,這樣的經(jīng)過排序之后就會出現(xiàn)變形,漏檢測,
            rect = pts1
        else:
            rect = self.order_points(pts1)
        (tl, tr, br, bl) = rect

        """==>>計(jì)算ROI區(qū)域的長寬<<=="""
        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))

        """==>>獲取變換后圖片的坐標(biāo)點(diǎn)、獲得旋轉(zhuǎn)矩陣、同時(shí)進(jìn)行透視變換<<=="""
        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)     # 獲得旋轉(zhuǎn)矩陣
        roi = cv.warpPerspective(self.binary, matrix, (maxHeight, maxWidth))    # 獲取roi區(qū)域

        """==>>對獲取到的目標(biāo)區(qū)域進(jìn)行面積統(tǒng)計(jì)<<=="""
        contours = cv2.findContours(roi, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)[0]  # 發(fā)現(xiàn)最外邊輪廓
        area_list = []                              #定義一個(gè)列表用來儲存所有的面積
        for cnt in contours:
            area_list.append(cv.contourArea(cnt))
        if len(area_list) == 0:
            max_cnts = 0                            # 如果區(qū)域沒有面積,sum會報(bào)錯(cuò),所以需要單獨(dú)賦值為0
        else:
            max_cnts = sum(area_list)               # 獲取面積綜合

        area = maxWidth * maxHeight                 # ROI的一個(gè)面積
        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)
        # 利用連通域進(jìn)行不同輪廓畫出不同顏色
        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)  # 圖像權(quán)重疊加
        for i in range(1, len(centers)):
            cv2.drawMarker(result, (int(centers[i][0]), int(centers[i][1])), (0, 0, 255), 1, 20, 2)

        return color,result


def get_binary(img):
    # 圖像預(yù)處理
    blurred = cv.pyrMeanShiftFiltering(img, 10, 100)  # 邊緣保留濾波能夠進(jìn)行去噪是同時(shí)有效地保留邊緣
    gray = cv.cvtColor(blurred, cv.COLOR_BGR2GRAY)  # 進(jìn)行灰度化為二值化做準(zhǔn)備
    ret, binary = cv.threshold(gray, thresh=70, maxval=255, type=cv.THRESH_BINARY)  # 固定閾值二值化,將大于thresh得像素點(diǎn)設(shè)置為maxval,
    return  binary

# 創(chuàng)建文件進(jìn)行圖片保存
def make_dir_save_img(path,img, binary,open,color,result ):
    if not os.path.exists(name):  # 判斷是否存在
        os.makedirs( name)  # 不存在就創(chuàng)建文件夾
    if not os.path.exists("roi\\"+name):  # 判斷是否存在
        os.makedirs("roi\\" +name)  # 不存在就創(chuàng)建文件夾


    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)


if __name__ == '__main__':

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

    img  = cv.imread(path)   # 讀取圖片

    # 獲取二值化圖片
    binary = get_binary(img)


    # 創(chuàng)建實(shí)例
    seg = SegmentationConnectObject(img,binary)
    # 調(diào)用第一個(gè)函數(shù)開始執(zhí)行功能,返回二值化、開操作、黑底顏色、結(jié)果、原圖
    img, binary,open,color,result = seg.main_find_mindist_points()
    # 進(jìn)行圖片保存
    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()

四、效果

opencv粘連分割,計(jì)算機(jī)視覺,opencv,人工智能,目標(biāo)檢測,圖像處理
圖3.1 二值化操作(分割線畫在了上面)
opencv粘連分割,計(jì)算機(jī)視覺,opencv,人工智能,目標(biāo)檢測,圖像處理
圖3.2 開操作

opencv粘連分割,計(jì)算機(jī)視覺,opencv,人工智能,目標(biāo)檢測,圖像處理

圖3.3 粘連位置角點(diǎn)ROI提取

opencv粘連分割,計(jì)算機(jī)視覺,opencv,人工智能,目標(biāo)檢測,圖像處理

圖3.4 分割效果圖
opencv粘連分割,計(jì)算機(jī)視覺,opencv,人工智能,目標(biāo)檢測,圖像處理
圖3. 5 連通域分析染色圖
opencv粘連分割,計(jì)算機(jī)視覺,opencv,人工智能,目標(biāo)檢測,圖像處理
圖3. 6 圖片融合

五、聲明

  • 因?yàn)闆]用同分辨率下的多張瓶蓋圖片,本代碼沒進(jìn)行批量測量,同時(shí)因?yàn)閭€(gè)人能力有限,算法以及代碼都有不少需要地方,本次分享主要為代碼分享,后續(xù)如果有時(shí)間,我會整理,進(jìn)行每個(gè)步驟講解。謝謝大家的支持,如有問題請?jiān)u論區(qū)留意,大家一起討論進(jìn)步?。?!

六、 其他文章


1.理論系列:

第一章:pycharm、anaconda、opencv、pytorch、tensorflow、paddlex等環(huán)境配置大全總結(jié)【圖像處理py版本】

第二章:OpenCv算法的基本介紹與應(yīng)用

第三章:OpenCv圖片、視頻讀寫操作與基本應(yīng)用

第四章:OpenCv閾值分割/二值化(單通道、多通道圖片)總結(jié)


2.項(xiàng)目系列:

項(xiàng)目一:四六級改卷系統(tǒng)
==》項(xiàng)目二:實(shí)戰(zhàn)篇:粘連物體分割——利用幾何分割實(shí)現(xiàn)瓶蓋分割檢測
項(xiàng)目三:實(shí)戰(zhàn)篇:粘連物體分割——利用幾何分割實(shí)現(xiàn)硬幣分割檢測
項(xiàng)目四:實(shí)戰(zhàn)篇:粘連物體分割——利用幾何分割實(shí)現(xiàn)細(xì)胞分割檢測
項(xiàng)目五:實(shí)戰(zhàn)篇:粘連物體分割——利用分水嶺算法實(shí)現(xiàn)糖豆分割檢測文章來源地址http://www.zghlxwxcb.cn/news/detail-709097.html

到了這里,關(guān)于【實(shí)戰(zhàn)篇:粘連物體分割——利用幾何分割實(shí)現(xiàn)瓶蓋分割檢測】的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包