How to segment similar looking areas (color wise) inside a image that belong to biosamples with opencv and python?

邮差的信 提交于 2021-01-28 02:03:50

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!