问题
I'm trying to analyze images of bio-films of pseudomona, I'm doing this in order to find some kind of correlation between its grow and distribution with some independent variables. I've applied a segmentation to obtain a circular area of interest and now I was thinking in applying some color segmentation to the image with its HSV values to just leave the areas with bio-film. I've trying to think in a way to completely isolate all the areas that are important, I applied a bitwise_not to the image to see the negative and have found that is visually more easy to distinguish, all the areas that are yellowish have bacteria on it.
Original image:
Negative:
With the code I've written, I've got to segment big spots of the bacteria, but not all the areas that really have it.
import cv2
import numpy as np
import os
def color_segmentation(image):
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
mask1 = cv2.inRange(hsv, (90,90,50), (179,255,160))
target = cv2.bitwise_and(image, image, mask=mask1)
return target
test = cv2.imread(path)
result = color_segmentation(test)
cv2.imshow('result', result)
I already know that the code it's really simple, so it didn't surprise me when I couldn't isolate all the areas of interest, do you think that if apply more masks could I extract all the yellowish areas? Or maybe someone could say an algorithm that's somewhat similar to what I'm looking. Thanks in advance to anyone interested.
Result:
回答1:
One idea is to perform Kmeans color quantization to cluster the image into a distinct amount of colors. Afterwards, we can convert the image to HSV format and perform color thresholding using cv2.inRange with a lower/upper color threshold to obtain a binary mask. Finally we apply this mask onto the original image using cv2.bitwise_and.
Original image ->
Kmeans color quantization with clusters=5
Notice the subtle difference in that the entire image is segmented into five colors. Here's a visualization of each color cluster and the color distribution percentage. Based on the color segmentation, we can estimate that the first three colors (ignoring black) have bacteria on it.
[ 67.70980019 86.19251507 121.19410086] 0.87%
[120.61108133 146.00169267 159.48142297] 9.78%
[0.18113609 0.22505063 0.25559479] 21.40%
[134.06236381 170.04397205 167.3696234 ] 23.44%
[140.53640479 189.4275781 171.19319177] 44.50%
Next we perform color thresholding to obtain a mask with this lower/upper color range
lower = np.array([84, 0, 0])
upper = np.array([179, 255, 255])
We apply the mask onto the original image to get our result
Remember how there were three color distributions we used to determine if there was bacteria? If we change the color threshold range, we can further segment the image into large, medium, and small regions of bacteria.
We can isolate only the large bacteria regions using this color range
lower = np.array([104, 0, 0])
upper = np.array([179, 255, 255])
Mask ->
Result
For the medium regions
lower = np.array([90, 0, 0])
upper = np.array([102, 255, 255])
Finally, to obtain the small regions
lower = np.array([84, 0, 0])
upper = np.array([98, 255, 255])
Code
import cv2
import numpy as np
# Kmeans color segmentation
def kmeans_color_quantization(image, clusters=8, rounds=1):
h, w = image.shape[:2]
samples = np.zeros([h*w,3], dtype=np.float32)
count = 0
for x in range(h):
for y in range(w):
samples[count] = image[x][y]
count += 1
compactness, labels, centers = cv2.kmeans(samples,
clusters,
None,
(cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10000, 0.0001),
rounds,
cv2.KMEANS_RANDOM_CENTERS)
centers = np.uint8(centers)
res = centers[labels.flatten()]
return res.reshape((image.shape))
# Load original image
original = cv2.imread('2.png')
# Perform kmeans color segmentation
kmeans = kmeans_color_quantization(original, clusters=5)
# Color threshold on kmeans image
hsv = cv2.cvtColor(kmeans, cv2.COLOR_BGR2HSV)
lower = np.array([84, 0, 0])
upper = np.array([179, 255, 255])
mask = cv2.inRange(hsv, lower, upper)
# Apply mask onto original image
result = cv2.bitwise_and(original, original, mask=mask)
result[mask==0] = (255,255,255)
# Display
cv2.imshow('kmeans', kmeans)
cv2.imshow('result', result)
cv2.imshow('mask', mask)
cv2.waitKey()
This HSV color thresholder script was used to determine the lower/upper color ranges
import cv2
import numpy as np
def nothing(x):
pass
# Load image
image = cv2.imread('1.png')
# Create a window
cv2.namedWindow('image')
# Create trackbars for color change
# Hue is from 0-179 for Opencv
cv2.createTrackbar('HMin', 'image', 0, 179, nothing)
cv2.createTrackbar('SMin', 'image', 0, 255, nothing)
cv2.createTrackbar('VMin', 'image', 0, 255, nothing)
cv2.createTrackbar('HMax', 'image', 0, 179, nothing)
cv2.createTrackbar('SMax', 'image', 0, 255, nothing)
cv2.createTrackbar('VMax', 'image', 0, 255, nothing)
# Set default value for Max HSV trackbars
cv2.setTrackbarPos('HMax', 'image', 179)
cv2.setTrackbarPos('SMax', 'image', 255)
cv2.setTrackbarPos('VMax', 'image', 255)
# Initialize HSV min/max values
hMin = sMin = vMin = hMax = sMax = vMax = 0
phMin = psMin = pvMin = phMax = psMax = pvMax = 0
while(1):
# Get current positions of all trackbars
hMin = cv2.getTrackbarPos('HMin', 'image')
sMin = cv2.getTrackbarPos('SMin', 'image')
vMin = cv2.getTrackbarPos('VMin', 'image')
hMax = cv2.getTrackbarPos('HMax', 'image')
sMax = cv2.getTrackbarPos('SMax', 'image')
vMax = cv2.getTrackbarPos('VMax', 'image')
# Set minimum and maximum HSV values to display
lower = np.array([hMin, sMin, vMin])
upper = np.array([hMax, sMax, vMax])
# Convert to HSV format and color threshold
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(hsv, lower, upper)
result = cv2.bitwise_and(image, image, mask=mask)
# Print if there is a change in HSV value
if((phMin != hMin) | (psMin != sMin) | (pvMin != vMin) | (phMax != hMax) | (psMax != sMax) | (pvMax != vMax) ):
print("(hMin = %d , sMin = %d, vMin = %d), (hMax = %d , sMax = %d, vMax = %d)" % (hMin , sMin , vMin, hMax, sMax , vMax))
phMin = hMin
psMin = sMin
pvMin = vMin
phMax = hMax
psMax = sMax
pvMax = vMax
# Display result image
cv2.imshow('image', result)
if cv2.waitKey(10) & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
来源:https://stackoverflow.com/questions/60272082/how-to-segment-similar-looking-areas-color-wise-inside-a-image-that-belong-to