範例說明
本文為參考下面的文章:
Image Segmentation with Distance Transform and Watershed Algorithm
這篇文章是OpenCV官方網站上的一篇教程,介紹了如何使用distanceTransform函數進行圖像分割。在這篇教程中,作者首先介紹了distanceTransform函數的基本概念和用法,然後通過一個實例演示了如何使用distanceTransform函數對圖像進行分割。
範例程式碼
以下為程式範例
from __future__ import print_function import cv2 as cv import numpy as np import argparse import random as rng rng.seed(12345) parser = argparse.ArgumentParser(description='Code for Image Segmentation with Distance Transform and Watershed Algorithm.\ Sample code showing how to segment overlapping objects using Laplacian filtering, \ in addition to Watershed and Distance Transformation') parser.add_argument('--input', help='Path to input image.', default='cards.png') args = parser.parse_args() src = cv.imread(cv.samples.findFile(args.input)) if src is None: print('Could not open or find the image:', args.input) exit(0) # Show source image cv.imshow('Source Image', src) src[np.all(src == 255, axis=2)] = 0 # Show output image cv.imshow('Black Background Image', src) kernel = np.array([[1, 1, 1], [1, -8, 1], [1, 1, 1]], dtype=np.float32) # do the laplacian filtering as it is # well, we need to convert everything in something more deeper then CV_8U # because the kernel has some negative values, # and we can expect in general to have a Laplacian image with negative values # BUT a 8bits unsigned int (the one we are working with) can contain values from 0 to 255 # so the possible negative number will be truncated imgLaplacian = cv.filter2D(src, cv.CV_32F, kernel) sharp = np.float32(src) imgResult = sharp - imgLaplacian # convert back to 8bits gray scale imgResult = np.clip(imgResult, 0, 255) imgResult = imgResult.astype('uint8') imgLaplacian = np.clip(imgLaplacian, 0, 255) imgLaplacian = np.uint8(imgLaplacian) #cv.imshow('Laplace Filtered Image', imgLaplacian) cv.imshow('New Sharped Image', imgResult) bw = cv.cvtColor(imgResult, cv.COLOR_BGR2GRAY) _, bw = cv.threshold(bw, 40, 255, cv.THRESH_BINARY | cv.THRESH_OTSU) cv.imshow('Binary Image', bw) dist = cv.distanceTransform(bw, cv.DIST_L2, 3) # Normalize the distance image for range = {0.0, 1.0} # so we can visualize and threshold it cv.normalize(dist, dist, 0, 1.0, cv.NORM_MINMAX) cv.imshow('Distance Transform Image', dist) _, dist = cv.threshold(dist, 0.4, 1.0, cv.THRESH_BINARY) # Dilate a bit the dist image kernel1 = np.ones((3,3), dtype=np.uint8) dist = cv.dilate(dist, kernel1) cv.imshow('Peaks', dist) dist_8u = dist.astype('uint8') # Find total markers _, contours, _ = cv.findContours(dist_8u, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE) # Create the marker image for the watershed algorithm markers = np.zeros(dist.shape, dtype=np.int32) # Draw the foreground markers for i in range(len(contours)): cv.drawContours(markers, contours, i, (i+1), -1) # Draw the background marker cv.circle(markers, (5,5), 3, (255,255,255), -1) markers_8u = (markers * 10).astype('uint8') cv.imshow('Markers', markers_8u) cv.watershed(imgResult, markers) #mark = np.zeros(markers.shape, dtype=np.uint8) mark = markers.astype('uint8') mark = cv.bitwise_not(mark) # uncomment this if you want to see how the mark # image looks like at that point #cv.imshow('Markers_v2', mark) # Generate random colors colors = [] for contour in contours: colors.append((rng.randint(0,256), rng.randint(0,256), rng.randint(0,256))) # Create the result image dst = np.zeros((markers.shape[0], markers.shape[1], 3), dtype=np.uint8) # Fill labeled objects with random colors for i in range(markers.shape[0]): for j in range(markers.shape[1]): index = markers[i,j] if index > 0 and index <= len(contours): dst[i,j,:] = colors[index-1] # Visualize the final image cv.imshow('Final Result', dst) cv.waitKey()
distanceTransform
distanceTransform函數是OpenCV中的一個函數,用於計算圖像中每個非零點到最近背景像素的距離。distanceTransform函數的第二個Mat矩陣參數dst保存了每個點與最近的零點的距離信息,圖像上越亮的點,代表了離零點的距離越遠。在這篇文章中,作者通過一個實例演示了如何使用distanceTransform函數對圖像進行分割。
在這個實例中,作者首先讀取了一張灰度圖像,然後使用threshold函數對圖像進行二值化處理。接著,作者使用distanceTransform函數計算了圖像中每個非零點到最近背景像素的距離,並將結果保存在了一個Mat矩陣中。最後,作者使用threshold函數對Mat矩陣進行二值化處理,得到了一張分割後的圖像。
需要注意的是,在使用distanceTransform函數時,需要先將圖像進行二值化處理。此外,在計算距離時,可以選擇歐氏距離、L1距離或L-infinity距離等不同的計算方式。
處理的過程圖片