python實現批量處理圖片:K-means聚類分割、開運算、畫目標區域框,切割目標區域

 做SAR圖像分類預處理時用到K-means聚類把前景後景分開。由於聚類效果不太理想,總有些錯分的像素點和目標區域不閉合的情況,且目標區域的邊緣也不夠平滑,所以在K-means之後還進行了一些後續操作,包括二值化處理,開運算等操作,再進行目標區域定位畫框,效果就好很多。

完整代碼和註釋如下:

# -*- coding: utf-8 -*-
# autho:xier
​​​​​​​
import cv2
import os
import math
import numpy as np
import PIL.Image as image
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from pylab import mpl
mpl.rcParams['font.sans-serif'] = 'NSimSun, Times New Roman'

# 加載圖片,轉成矩陣
def load_data(file_path):
    f = open(file_path, 'rb')  # 二進制打開
    data = []
    img = image.open(f)  # 以列表形式返回圖片像素值
    m, n = img.size  # 圖片大小
    for i in range(m):
        for j in range(n):  # 將每個像素點RGB顏色處理到0-1範圍內並存放data
            x = img.getpixel((i, j))
            data.append([x/256.0])
    f.close()
    return np.mat(data), m, n  # 以矩陣型式返回data,圖片大小

def K_means(img_data, row, col):
    label = KMeans(n_clusters=2, n_init=40, init='k-means++').fit_predict(img_data)  # 聚成兩類
    label = label.reshape([row, col])  # 聚類獲得每個像素所屬的類別
    if np.sum(label) >= row * col/2:  #分類相反
        label = np.abs(np.ones((row, col)) - label)
    pic_k = image.new("L", (row, col))  # 創建一張新的灰度圖保存聚類後的結果
    for i in range(row):  # 根據所屬類別向圖片中添加灰度值
        for j in range(col):
            pic_k.putpixel((i, j), int(256 / (label[i][j] + 1)))
    return pic_k

# 對K_means聚類分割後的圖像進行閾值分割轉成二值圖像
def Thresh_and_blur(img):

    (_, thresh) = cv2.threshold(img, 130, 255, cv2.THRESH_BINARY)

    return thresh

# 用數字形態學先腐蝕掉噪聲再進行膨脹(開運算)
def image_morphology(thresh):
    # 建立一個橢圓核函數
    kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (10, 10))
    # 執行圖像形態學
    opened = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)
    # closed = cv2.morphologyEx(opened, cv2.MORPH_CLOSE, kernel)
    #opened = cv2.erode(opened, None, iterations=4)  # 腐蝕4次
    #opened = cv2.dilate(opened, None, iterations=4)  # 膨脹4次
    return opened

def findcnts_and_box_point(opened):
    # 這裏opencv3返回的是三個參數,源圖像、輪廓信息、可選參數
    # 輪廓檢索模式:cv2.RETR_LIST表示提取所有輪廓並記錄在列表
    # 輪廓逼近方法:cv2.CHAIN_APPROX_SIMPLE,壓縮水平、垂直、對角元素,保留終點座標,如矩形輪廓用4個角點表示
    (_, cnts, _) = cv2.findContours(opened.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
    c = sorted(cnts, key=cv2.contourArea, reverse=True)
    c = c[1]
    # compute the rotated bounding box of the largest contour
    rect = cv2.minAreaRect(c)  # 生成最小外接矩形,retval包含中心座標、矩形寬高和旋轉角度
    box = np.int0(cv2.boxPoints(rect))  # 得到旋轉矩陣四個頂點座標

    return box

def drawcnts_and_cut(original_img, box):
    # draw a bounding box arounded the detected barcode and display the image
    draw_img = cv2.drawContours(original_img.copy(), [box], -1, (0, 0, 255), 3)
    # 截取圖像
    Xs = [i[0] for i in box]
    Ys = [i[1] for i in box]
    x1 = min(Xs)
    x2 = max(Xs)
    y1 = min(Ys)
    y2 = max(Ys)
    y_mid = y1 + math.ceil((y2 - y1)/2)
    x_mid = x1 + math.ceil((x2 - x1) / 2)

    crop_img = original_img[y_mid-25:y_mid+25, x_mid-25:x_mid+25]  # 裁成50*50目標圖像

    return draw_img, crop_img

def walk():

    original_Folder = '自己存放圖片的文件夾'
    OR_Vector = os.listdir(original_Folder)  # 讀取待處理文件夾中所有的文件
    for k in range(len(OR_Vector)):
        # 取一個類別文件夾
        Class_Folder = os.path.join('%s\%s' % (original_Folder, OR_Vector[k]))
        # 讀取該類別文件夾的所有圖片
        CF_Tensor = os.listdir(Class_Folder)
        for p in range(len(CF_Tensor)):  # 取一張圖片
            # 取一張圖片
            Image_Path = os.path.join('%s\%s' % (Class_Folder, CF_Tensor[p]))
            original_img = cv2.imread(Image_Path)
            img_data, row, col = load_data(Image_Path)
            pic_k = K_means(img_data, row, col)
            pic_k = np.asarray(pic_k)
            thresh = Thresh_and_blur(pic_k)
            opened = image_morphology(thresh)
            box = findcnts_and_box_point(opened)
            draw_img, crop_img = drawcnts_and_cut(original_img, box)

            # 保存切割後的圖片
            # Save_Folder = 'F:\pycharm\\test_IO\\MSTAR-10_denoise_enl4\\train_denoise_enl4_segment'
            # SA_Vector = os.listdir(Save_Folder)  # 讀取保存的文件夾中所有的文件
            # Class_Folder2 = os.path.join('%s\%s' % (Save_Folder, SA_Vector[k]))
            # Save_Path = os.path.join('%s\%s' % (Class_Folder2, CF_Tensor[p]))
            # cv2.imwrite(Save_Path, crop_img)

            titles = [u'去噪後圖像', u'K-means聚類後', u'二值化處理', u'開運算', u'定位目標區域', u'切割後的圖像']
            images = [original_img, pic_k, thresh, opened, draw_img, crop_img] #
            for i in range(6):
                plt.subplot(2, 3, i + 1), plt.imshow(images[i], 'gray')
                plt.title(titles[i])
                plt.xticks([]), plt.yticks([])
            plt.show()
            cv2.waitKey(20180407)

walk()

結果展示如下:

k-means聚類及目標區域切割
圖像K-means分割及目標區域切割

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章