Image Processing:How to extract cementing matrix between different circles using opencv - opencv

A CT scanning image, in which the circles is connected by cement matrix. I want to extract the volume of cement matrix. However, I cannot find perfect threshold value to divide circles and cement matrix by using Watershed algorithm.
I also have tried to use OpenCV HoughCircles and findContours to detect circles. But the result is perfect enough. Perhaps I am just not familiar enough with the OpenCV. Attached is my image that I need to extract cementing matrix between different circles. You should be able to see it clearly with your eyes. However, none of the circle detection algorithms seem to work.
Note I even looked at and tried the solution here so it is not a duplicate of that question: Opencv divide contacted circles into single. enter link description here
And another solution:OpenCV detect partial circle with noise enter link description here
This is my source image that I need to use.
Original Image:
HoughCircles Image:
The code:
enter code here
import cv2
import numpy as np
def houghdetect(image,img):
circles = cv2.HoughCircles(image, cv2.HOUGH_GRADIENT, 1, 50, param1 = 20, param2 = 27, minRadius = 25, maxRadius = 50)
circles = np.uint16(np.around(circles))
for i in circles[0, 1:]:
cv2.circle(img, (i[0], i[1]), i[2], (0, 0, 255), 2)
cv2.namedWindow('detect_circle', 0)
cv2.resizeWindow('detect_circle', 699, 575)
cv2.imshow('detect_circle', img)
img = cv2.imread('C:\THU\python\learn\outputtif\\5.jpg')
dst = cv2.GaussianBlur(img, (3,3), 0)
gray = cv2.cvtColor(dst, cv2.COLOR_BGR2GRAY)
ret, threshold = cv2.threshold(gray, 135, 255, cv2.THRESH_TOZERO)
Gthreshold = cv2.GaussianBlur(threshold, (5,5), 0)
cv2.namedWindow('Gthreshold', 0)
cv2.resizeWindow('Gthreshold', 699, 575)
cv2.imshow("Gthreshold", Gthreshold)
houghdetect(Gthreshold, img)
cv2.waitKey()
cv2.destroyAllWindows()

Related

How to improve performance of cell segmentation using watershed algorithm with opencv-python

I have tried to segment cells in H&E-stained histopathological images using Watershed algorithm of opencv-python.
The code I used is totally same as Docs opencv code in link below.
Watershed Code Source
But as you see the result, the performance of segmentation is not that much good.
Some cells could not be detected.
I want to detect all of cells at a time in that image.
In the case of cell in biomedical, I think this is more sensitive than normal object segmentation.
In original code, I added and applied two Blur algorithms before using cv2.morphologyEx().
img = cv2.imread("Path_of_Image")
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# Convert to Binary Image
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
kernel = np.ones((3, 3), np.uint8)
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=2)
sure_bg = cv2.dilate(opening, kernel, iterations=3)
dist_transform = cv2.distanceTransform(opening, cv2.DIST_L2, 5)
ret, sure_fg = cv2.threshold(dist_transform, 0.5*dist_transform.max(), 255, 0)
sure_fg = np.uint8(sure_fg)
unknown = cv2.subtract(sure_bg, sure_fg)
ret, markers = cv2.connectedComponents(sure_fg)
markers = markers + 1
markers[unknown == 255] = 0
markers = cv2.watershed(img_rgb, markers)
img_rgb[markers == -1] = [255, 0, 0]
images = [gray, thresh, sure_bg, dist_transform, sure_fg, unknown, markers, img_rgb]
titles = ['Gray','Binary','Sure BG','Distance','Sure FG','Unknow','Markers','Result']
plt.figure(figsize=(12, 12))
for i in range(len(images)):
plt.subplot(2, 4, i + 1),
plt.imshow(images[i], cmap='gray'),
plt.title(titles[i]),
plt.xticks([]),plt.yticks([])
# plt.figure(figsize= (5, 5))
# plt.tight_layout()
plt.show()
There was a litte bit improvement, but still need changes.
How can I deal with this problem? Do I have to more examine Marker value or something?
I wonder your thinking.
Thank you in advance.
[Add]
This is Original Image.
Original Image

Detect rectangular table from ASUS Xtion Live Pro IR image

I have an IR image with a resolution of (240 x 320), datatype: float32 as you can see here:
The raw npy image is here.
My objective is to detect the table (brown contour) in order to crop this region as a ROI.
What I have tried so far is to do:
Histogram equalization to increase contrast,
Gaussian Blurring to reduce the noise, and
contour detection to find the rectangular table in the middle of the image.
Note that the table in my case is installed on wheels, and hence it might slightly move so I want to detect it dynamically, and not use its fixed position inside the image.
The code I have used is:
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import numpy as np
import matplotlib.pyplot as plt
import cv2
import random as rng
path = ""
# Read the numpy array
ir_raw = np.load(path+"ir.npy") # (240, 320) float32
ir = np.uint8((ir_raw/ir_raw.max()) * 255)
# Histogram equalization (Contrast Adjustment)
heq_ir = cv2.equalizeHist(ir)
# Gaussian smoothing (Noise Removal)
g_blur_ir = cv2.GaussianBlur(heq_ir, (5,5), 0)
# Otsu Thresholding
_, thresh_ir = cv2.threshold(g_blur_ir, 120, 255, cv2.THRESH_BINARY +
cv2.THRESH_OTSU)
# Find contours
contours, hierarchy = cv2.findContours(thresh_ir, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# Draw contours
rng.seed(12345)
drawing = np.zeros((thresh_ir.shape[0], thresh_ir.shape[1], 3), dtype=np.uint8)
for i in range(len(contours)):
color = (rng.randint(0,256), rng.randint(0,256), rng.randint(0,256))
cv2.drawContours(drawing, contours, i, color, 2, cv2.LINE_8, hierarchy, 0)
plt.subplot(121)
plt.imshow(heq_ir)
plt.title("IR")
plt.subplot(122)
plt.imshow(drawing)
plt.title("IR contours")
plt.show()
Can you please tell me how can I detect the rectangular table in order to crop it as a ROI? thanks in advance.
Assuming the following, the table always has same area (well duh) but in the case below its always the largest object detected (the code should be easily to amend to filter out objects of different areas though).
I've filtered out all contours that have a different area to the table contour (process of elimination until I found the table then set the area threshold accordingly) & then fitted a rectangle to that contour. It is possible to fit skewed rectangles in OpenCV as well but I havent in this case. (EDIT: code for skewed rectangles added)
Your ROI boundary is in boundRect
for i in range(len(contours)):
if cv2.contourArea(contours[i]) > 10000:
color = (rng.randint(0,256), rng.randint(0,256), rng.randint(0,256))
cv2.drawContours(drawing, contours, i, color, 2, cv2.LINE_8, hierarchy, 0)
# For unrotated bounding rectangle
boundRect = cv2.boundingRect(contours[i])
cv2.rectangle(drawing, (int(boundRect[0]), int(boundRect[1])), (int(boundRect[0]+boundRect[2]), int(boundRect[1]+boundRect[3])), (255, 255, 255), 2)
# For minimal bounding rectangle that will rotate with table rotation
rect = cv2.minAreaRect(contours[i])
box = cv2.boxPoints(rect)
box = np.int0(box)
cv2.drawContours(drawing, [box], 0, (255, 0, 255), 2)
print(cv2.contourArea(contours[i]))
Ouput,

houghlinesp and thresholding

I am using opencv Houghlinesp to detect lines in a parking lot. Here is the source image
When I did a hough transform-p to detect the lines, I got final image like this.
It did detect empty spaces. Any ideas how these noisy lines on top of the cars can be removed? Or any direction on alternative algorithms or approaches highly appreciated.
img = cv.imread('Parking-Lot.jpg')
threshold=100
minLineLength = 60
rho=2
maxLineGap=20
theta = np.pi/180
edges = cv.Canny(img, 100, 200)
lines = cv.HoughLinesP(edges, rho, theta, threshold, np.array([]), minLineLength =minLineLength , maxLineGap=maxLineGap)
for i in range(len(lines)):
for line in lines[i]:
cv.line(img, (line[0],line[1]), (line[2],line[3]), (0,255,0), 2)
cv2.imwrite("lines.jpg", img)
You can remove most of the noise by thresholding your image before you apply the edge detection. That way you will remove (most of) the cars and keep your white space lines you are interested in:
import cv2
import numpy as np
img = cv2.imread('Parking-Lot.jpg')
threshold=100
minLineLength = 60
rho=2
maxLineGap=20
theta = np.pi/180
# here you convert the image to grayscale and then threshhold to binary
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(gray,180,255,cv2.THRESH_BINARY)
# continue with the threshholded image instead
edges = cv2.Canny(thresh, 100, 200)
lines = cv2.HoughLinesP(edges, rho, theta, threshold, np.array([]), minLineLength =minLineLength , maxLineGap=maxLineGap)
for i in range(len(lines)):
for line in lines[i]:
cv2.line(img, (line[0],line[1]), (line[2],line[3]), (0,255,0), 2)
cv2.imwrite("lines.jpg", img)
This will yield you a much cleaner result:
Feel free to experiment with the threshold parameters; you will need to find a threshold that excludes most of the cars while keeping all the lines that you want to detect.

How to whiten background and blaken grid in a same image

I have an image like this. I wan to use HoughLine detection but the image is too dark to recognize the line. Is there a way that can whiten the background and blacken the grid? Is there any algorithms in openCV or python that I can apply? Thank you
I try to dilate the image first, then medianBlur it, so I get the background. Use the original gray image to sub the background, I get the frontground ( that is the grids). Then do some other steps, I get the result like this.
The code is as follow:
#!/usr/bin/python3
# 2017.10.04 19:37:43 CST
filename = "data/paper.png"
img = cv2.imread(filename)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
## do morph-dilate-op
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5))
dilated = cv2.morphologyEx(gray, cv2.MORPH_DILATE, kernel)
diff1 = 255 - cv2.subtract(dilated, gray)
## do medianBlur
median = cv2.medianBlur(dilated, 15)
diff2 = 255 - cv2.subtract(median, gray)
## do normalize
normed = cv2.normalize(diff2,None, 0, 255, cv2.NORM_MINMAX )
## save the result
dst = np.hstack((gray, normed))
cv2.imwrite("result_paper1.png", dst)
res = np.hstack((gray,dilated, diff1, median, diff2, normed))
cv2.imwrite("result_paper2.png", res)
You should try a form of localized adaptive thresholding.
In OpenCV this is called cv2.adaptiveThreshold.
See here: http://docs.opencv.org/master/d7/d4d/tutorial_py_thresholding.html for a python example.
The code (from the source above):
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('sudoku.png',0)
img = cv2.medianBlur(img,5)
ret,th1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
th2 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_MEAN_C,\
cv2.THRESH_BINARY,11,2)
th3 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,\
cv2.THRESH_BINARY,11,2)
titles = ['Original Image', 'Global Thresholding (v = 127)',
'Adaptive Mean Thresholding', 'Adaptive Gaussian Thresholding']
images = [img, th1, th2, th3]
for i in range(4):
plt.subplot(2,2,i+1),plt.imshow(images[i],'gray')
plt.title(titles[i])
plt.xticks([]),plt.yticks([])
plt.show()
Your image has poor contrast and inconsistent light. You have to make some preprocessing (c++ code here):
cv::Mat img = cv::imread("E:\\Workspace\\KS\\excercise\\oBwBH.jpg", 0);
cv::Mat workingMat;
cv::GaussianBlur(img, workingMat, cv::Size(101, 101), 31, 31); //high blur to extract background light
img = img - 0.7*work; //adjust light level
cv::normalize(img, img, 0, 255, cv::NORM_MINMAX); \\use whole range
cv::medianBlur(img, img, 5); \\remove noise
cv::Canny(img, work, 100, 200); \\extract lines; you could do hough lines instead since it has canny inside.
Results (from left to right, canny has all lines, in preview there is some compression issue):

Why HoughCircles returns 0 circles while trying to detect irises?

I am trying to detect the eyes' irises but HoughCircles returns 0 circles.
The input image(eyes) is:
Then I made the following things with this image:
cvtColor(eyes, gray, CV_BGR2GRAY);
morphologyEx(gray, gray, 4,cv::getStructuringElement(cv::MORPH_RECT,cv::Size(3,3)));
threshold(gray, gray, 0, 255, THRESH_OTSU);
vector<Vec3f> circles;
HoughCircles(gray, circles, CV_HOUGH_GRADIENT, 2, gray.rows/4);
if (circles.size())
cout << "found" << endl;
So the final gray image looks like this:
I've found this question Using HoughCircles to detect and measure pupil and iris but it didn't help me despite the similarity with my issue.
So why does HoughCircles return 0 circles while trying to detect irises?
If someone knows any better way to find irises, you are welcome.
I have faced the exact same issue for the same problem. Turns out houghcircles is not a very good method for detecting not-so-well-formed circles.
Feature detection methods like MSER work better in these cases.
import cv2
import math
import numpy as np
import sys
def non_maximal_supression(x):
for f in features:
distx = f.pt[0] - x.pt[0]
disty = f.pt[1] - x.pt[1]
dist = math.sqrt(distx*distx + disty*disty)
if (f.size > x.size) and (dist<f.size/2):
return True
thresh = 70
img = cv2.imread(sys.argv[1])
bw = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
detector = cv2.FeatureDetector_create('MSER')
features = detector.detect(bw)
features.sort(key = lambda x: -x.size)
features = [ x for x in features if x.size > 70]
reduced_features = [x for x in features if not non_maximal_supression(x)]
for rf in reduced_features:
cv2.circle(img, (int(rf.pt[0]), int(rf.pt[1])), int(rf.size/2), (0,0,255), 3)
cv2.imshow("iris detection", img)
cv2.waitKey()
Alternatively you can try convolutional filters.
EDIT:
For the ones who have issues with c++ MSER, here is a basic gist.

Resources