Skip to content Skip to sidebar Skip to footer

Image Processing - Eliminate Arc-like Smears

I am dealing with this kind of image (upper is post-processed) (lower is raw) So, first I converted the grayscale image into pure black and white binary image. I am interested in

Solution 1:

You can just detect circle of the right size with skimage's methods hough_circle and hough_circle_peaks and cut it out.

Here I adapted my previous answer to your other question to do this:

# skimage version 0.14.0import math
import numpy as np
import matplotlib.pyplot as plt

from skimage import color
from skimage.io import imread
from skimage.transform import hough_circle, hough_circle_peaks
from skimage.feature import canny
from skimage.draw import circle
from skimage.util import img_as_ubyte

INPUT_IMAGE = 'dish1.png'# input image name
BEST_COUNT = 1# how many circles to detect (one dish)
MIN_RADIUS = 100# min radius of the Petri dish
MAX_RADIUS = 122# max radius of the Petri dish (in pixels)
LARGER_THRESH = 1.2# circle is considered significantly larger than another one if its radius is at least so much bigger
OVERLAP_THRESH = 0.1# circles are considered overlapping if this part of the smaller circle is overlappingdefcircle_overlap_percent(centers_distance, radius1, radius2):
    '''
    Calculating the percentage area overlap between circles
    See Gist for comments:
        https://gist.github.com/amakukha/5019bfd4694304d85c617df0ca123854
    '''
    R, r = max(radius1, radius2), min(radius1, radius2)
    if centers_distance >= R + r:
        return0.0elif R >= centers_distance + r:
        return1.0
    R2, r2 = R**2, r**2
    x1 = (centers_distance**2 - R2 + r2 )/(2*centers_distance)
    x2 = abs(centers_distance - x1)
    y = math.sqrt(R2 - x1**2)
    a1 = R2 * math.atan2(y, x1) - x1*y
    if x1 <= centers_distance:
        a2 = r2 * math.atan2(y, x2) - x2*y
    else:
        a2 = math.pi * r2 - a2
    overlap_area = a1 + a2
    return overlap_area / (math.pi * r2)

defcircle_overlap(c1, c2):
    d = math.sqrt((c1[0]-c2[0])**2 + (c1[1]-c2[1])**2)
    return circle_overlap_percent(d, c1[2], c2[2])

definner_circle(cs, c, thresh):
    '''Is circle `c` is "inside" one of the `cs` circles?'''for dc in cs:
        # if new circle is larger than existing -> it's not insideif c[2] > dc[2]*LARGER_THRESH: continue# if new circle is smaller than existing one...if circle_overlap(dc, c)>thresh:
            # ...and there is a significant overlap -> it's inner circlereturnTruereturnFalse# Load picture and detect edges
image = imread(INPUT_IMAGE, 1)
image = img_as_ubyte(image)
edges = canny(image, sigma=3, low_threshold=10, high_threshold=50)

# Detect circles of specific radii
hough_radii = np.arange(MIN_RADIUS, MAX_RADIUS, 2)
hough_res = hough_circle(edges, hough_radii)

# Select the most prominent circles (in order from best to worst)
accums, cx, cy, radii = hough_circle_peaks(hough_res, hough_radii)

# Determine BEST_COUNT circles to be drawn
drawn_circles = []
for crcl inzip(cy, cx, radii):
    # Do not draw circles if they are mostly inside better fitting onesifnot inner_circle(drawn_circles, crcl, OVERLAP_THRESH):
        # A good circle found: exclude smaller circles it covers
        i = 0while i<len(drawn_circles):
            if circle_overlap(crcl, drawn_circles[i]) > OVERLAP_THRESH:
                t = drawn_circles.pop(i)
            else:
                i += 1# Remember the new circle
        drawn_circles.append(crcl)
    # Stop after have found more circles than needediflen(drawn_circles)>BEST_COUNT:
        break

drawn_circles = drawn_circles[:BEST_COUNT]

# Draw circle and cut it out
colors  = [(250, 0, 0), (0, 250, 0), (0, 0, 250)]
fig, ax = plt.subplots(ncols=1, nrows=3, figsize=(10, 4))
color_image = color.gray2rgb(image)
black_image = np.zeros_like(image)
for center_y, center_x, radius in drawn_circles[:1]:
    circy, circx = circle(center_y, center_x, radius, image.shape)
    color = colors.pop(0)
    color_image[circy, circx] = color
    black_image[circy, circx] = image[circy, circx]
    colors.append(color)

# Output
ax[0].imshow(image, cmap=plt.cm.gray)        # original image
ax[1].imshow(color_image)                    # detected circle
ax[2].imshow(black_image, cmap=plt.cm.gray)  # cutout
plt.show()

Output:

Original Petri dish image, detected dish, cutout

Again, as in my previous answer, most of the code here is doing "hierarchy" computation to find the biggest best fitting circle.

Post a Comment for "Image Processing - Eliminate Arc-like Smears"