How to extract the white rings in the given image - matlab

I have an image of a robot moving, I need to extract the white rings
in order to find the midpoint of the robot. But thresholding is not giving correct result:
What method should I try to extract only the white rings.
%code to get second image
img=imread('data\Image13.jpg');
hsv=rgb2hsv(img);
bin=hsv(:,:,3)>0.8;

Something like that?
import cv2
import numpy as np
# get bounding rectangles of contours
img = cv2.imread('img.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 200, 255, cv2.THRESH_BINARY)
contours, _ = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# filter contours by area and width
contours = [c for c in contours if (50 < cv2.contourArea(c) < 500) and cv2.boundingRect(c)[2] > 20]
# draw contours on empty mask
out = np.zeros(thresh.shape, dtype=np.uint8)
cv2.drawContours(out, contours, -1, 255, -1)
cv2.imwrite('out.png', out)
Output:

Related

Is there an algorithm to find known size and shape object in an image?

Since image processing and computer vision aren't of my field of study I'm having difficulty finding an algorithm that can identify the positions of rectangles of known size and proportion in certain images to automate a process.
These are grayscale images containing some circles and only one or none white rectangle with rounded edges, as can be seen in the example figure below.
3 different imagens with the "same" retangle to be found
Thank you
Try OpenCV, it stands for Open Computer Vision. It’s free. This is written in Python.
import cv2
import numpy as np
img = cv2.imread("C:\\Users\\mogar\\Desktop\\temp.jpg")
grayImage = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(grayImage, 160, 255, cv2.THRESH_BINARY)
kernel = np.ones((5,5),np.uint8)
thresh = cv2.erode(thresh,kernel,iterations = 1)
#thresh = np.invert(thresh)
cv2.imshow("Threholded Image", thresh)
cv2.waitKey(0) & 0xFF == ord('q')
cv2.destroyAllWindows()
_, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
for cnts in contours:
rect = cv2.minAreaRect(cnts)
box = cv2.boxPoints(rect)
box = np.int0(box)
(x,y),(w,h),angle = rect
w = int(w)
h = int(h)
area = w*h
if area > 10000 and area < 100000:
print("Area Check", area)
cv2.drawContours(img, [box], 0, (0,0,255), 5)
small = cv2.resize(img, (0,0), fx=0.3, fy=0.3)
cv2.imshow("Contours", small)
cv2.waitKey(0) & 0xFF == ord('q')
cv2.destroyAllWindows()
You may need to adjust some of the threshold values and area values so that you'll be enclosing only the rectangles. You'll notice the rectangles are not fully enclosed right now, that is literally because the text is getting in the way and cutting the rectangles in half. If you had a clean image; I'm sure this would work great. If you have any questions please don't hesitate the ask, but it may take some time before I can answer.

Applying adaptive thresholding on Canny edge detection

I want to remove the blurred background of images in my project dataset, and I already get a pretty nice solution in here using Canny edge detection. I want to apply an adaptive thresholding on the double threshold value requirements of Canny. I appreciate any help on this.
imageNames = glob.glob(r"C:\Users\Bikir\Pictures\rTest\*.jpg")
count=0
for i in imageNames:
img = Image.open(i)
img = np.array(img)
# grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# canny - I want this two values (0 and 150) to be adaptive in this case
canned = cv2.Canny(gray, 0, 150)
# dilate to close holes in lines
kernel = np.ones((3,3),np.uint8)
mask = cv2.dilate(canned, kernel, iterations = 1);
# find contours
# Opencv 3.4, if using a different major version (4.0 or 2.0), remove the first underscore
_, contours, _ = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE);
# find the biggest contour
biggest_cntr = None;
biggest_area = 0;
for contour in contours:
area = cv2.contourArea(contour);
if area > biggest_area:
biggest_area = area;
biggest_cntr = contour;
# draw contours
crop_mask = np.zeros_like(mask);
cv2.drawContours(crop_mask, [biggest_cntr], -1, (255), -1);
# opening + median blur to smooth jaggies
crop_mask = cv2.erode(crop_mask, kernel, iterations = 5);
crop_mask = cv2.dilate(crop_mask, kernel, iterations = 5);
crop_mask = cv2.medianBlur(crop_mask, 21);
# crop image
crop = np.zeros_like(img);
crop[crop_mask == 255] = img[crop_mask == 255];
img = im.fromarray(crop)
img.save(r"C:\Users\Bikir\Pictures\removed\\"+str(count)+".jpg")
count+=1

Extract objects (fingerprint and signature) from an image using OpenCV and python

At my website I receive an image contains the user fingerprint and signature, I wan't to extract these two pieces of information.
for example:
Original Image
import os
import cv2
import numpy as np
def imshow(label, image):
cv2.imshow(label, image)
cv2.waitKey(0)
cv2.destroyAllWindows()
#read image
rgb_img = cv2.imread('path')
rgb_img = cv2.resize(rgb_img, (900, 600))
gray_img = cv2.cvtColor(rgb_img, cv2.COLOR_BGR2GRAY)
Gray Image
#canny edge detection
canny = cv2.Canny(gray_img, 50, 120)
canny edge image
# Morphology Closing
kernel = np.ones((7, 23), np.uint8)
closing = cv2.morphologyEx(canny, cv2.MORPH_CLOSE, kernel)
Morphology Closing
# Find contours
contours, hierarchy = cv2.findContours(closing.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
# Sort Contors by area and then remove the largest frame contour
n = len(contours) - 1
contours = sorted(contours, key=cv2.contourArea, reverse=False)[:n]
copy = rgb_img.copy()
# Iterate through contours and draw the convex hull
for c in contours:
if cv2.contourArea(c) < 750:
continue
hull = cv2.convexHull(c)
cv2.drawContours(copy, [hull], 0, (0, 255, 0), 2)
imshow('Convex Hull', copy)
Image divided to parts
Now my goals are:
Know which part is the signature and which is the fingerprint
Resolve the contours overlapping if exist
P.S: I'm not sure if the previous steps are final so please if you have better steps tell me.
These are some hard examples i may wanna deal with
You can use morphology for finger print and signature selecting.
By example:
import cv2
import numpy as np
img = cv2.imread('fhZCs.png')
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
img=cv2.bitwise_not(img) #negate image
#color definition
blue_upper = np.array([130,255,255])
blue_lower = np.array([115,0,0])
#blue color mask (sort of thresholding, actually segmentation)
mask = cv2.inRange(hsv, blue_lower, blue_upper)
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (20,20))
finger=cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)
mask2=cv2.morphologyEx(finger, cv2.MORPH_DILATE, kernel)
signature=cv2.compare(mask2, mask, cv2.CMP_LT)
signature=cv2.morphologyEx(signature, cv2.MORPH_DILATE, kernel)
signature=cv2.bitwise_and(img, img, mask=signature)
signature=cv2.bitwise_not(signature)
finger=cv2.bitwise_and(img, img, mask=finger)
finger=cv2.bitwise_not(finger)
cv2.imwrite('finger.png', finger)
cv2.imwrite('signature.png',signature)

Determine the proportion of specific colors in an image

Do you have any idea how can I determine the proportion of Yellow (or Yellowish), Brown, and Red colour in a specific image? I tried to use HSV, but I could not find any threshold for H, S, and V for the aforementioned colours.
I attached a sample image.
So, let's do this one step at a time.
First how to know which color is represented by what value? For that, I referred to this stackoverflow question, from where you can get this HSV color map,
If you DuckDuckGo/Google/search for "HSV or HSL color map", you could find many examples.
Now, we can pick a color from the along the horizontal axis. We can use a single value e.g. 120 for dark blue or we can use a range of values e.g. 45 to 80 for all hues of green.
What I wasn't sure about was, how to define the,
proportion of Yellow (or Yellowish), Brown, and Red colour in a specific image
as you ask in your question.
I thought of then two ways to represent the color proportion.
Proportion of pixels containing some portion of that hue.
Proportion of the specific hue relative to all the hues in the image.
Then using the following script, you could get some numbers:
NOTE: (This the Python script, I originally posted. The corresponding Matlab script is further down the post.)
import cv2
import numpy as np
img = cv2.imread("D:\\lenna.jpg")
height_img, width_img, channels_img = img.shape
# Converts images from RGB to HSV
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
mask1 = cv2.inRange(hsv, (150, 0, 0), (150, 255,255)) #150 seems like pinkish
mask2 = cv2.inRange(hsv, (1,0,0), (20, 255, 255)) #1 to 20 seems orangish
total_num_of_pixels = height_img * width_img
all_colors = np.sum(hsv[:,:,:] > 0)
num_of_pixels_with_pinkish_component = np.sum(mask1 > 0)
num_of_pixels_with_orangish_component = np.sum(mask2 > 0)
print("%age of pixels with pinkish component:", "{:.2f}".format(num_of_pixels_with_pinkish_component/total_num_of_pixels * 100))
print("%age of pixels with orangish component:", "{:.2f}".format(num_of_pixels_with_orangish_component/total_num_of_pixels * 100))
print("%age of pinkish component in the entire HSV image:", "{:.2f}".format(num_of_pixels_with_pinkish_component/all_colors * 100))
print("%age of orangish in the entire HSV image:", "{:.2f}".format(num_of_pixels_with_orangish_component/all_colors * 100))
# To visualize the results
res1 = cv2.bitwise_and(img, img, mask=mask1)
res2 = cv2.bitwise_and(img, img, mask=mask2)
cv2.imshow('img', img)
cv2.imshow('mask1', mask1)
cv2.imshow('mask2', mask2)
cv2.imshow('res1', res1)
cv2.imshow('res2', res2)
# To save the output
cv2.imwrite('D:\\mask1.png', mask1)
cv2.imwrite('D:\\mask2.png', mask2)
cv2.imwrite('D:\\res1.png', res1)
cv2.imwrite('D:\\res2.png', res2)
Output:
%age of pixels with pinkish component: 0.41
%age of pixels with orangish component: 35.58
%age of pinkish component in the entire HSV image: 0.15
%age of orangish in the entire HSV image: 13.27
Here is how the output looks then:
MASK1 (150 on the hue axis seems pinkish)
MASK2 (1 ~ 20 on the hue axis seems orange)
RES1
RES2
Here is the equivalent MATLAB script.
close all;
clear all;
clc;
img = imread("/home/junglefox/Downloads/lenna.png");
figure, imshow(img), title('original image (RGB)');
img_size = size(img);
hsv_img = rgb2hsv(img);
hsv_img = im2uint8(hsv_img);
figure, imshow(hsv_img), title('original image in HSV');
% Orange component between 1 and 20 on the HSV map
minval = [1 0 0]; %// Define three element vector here for each colour plane i.e. [0 128 128];
maxval = [20 255 255]; %// Define three element vector here for each colour plane i.e. [0 128 128];
out = true(img_size(1), img_size(2));
for p = 1 : 3
out = out & (hsv_img(:,:,p) >= minval(p) & hsv_img(:,:,p) <= maxval(p));
end
figure, imshow(out), title('image of orange component in image only');
total_num_of_pixels = img_size(1) * img_size(2);
all_colors = sum(hsv_img(:,:,:) > 0);
num_of_pixels_with_orangish_component = sum(sum(out > 0));
percentage_orange = num_of_pixels_with_orangish_component/total_num_of_pixels * 100;
printf("percentage of orange component in all pixels:%d\n", percentage_orange);

Contour detection in MATLAB

I am trying to understand this code:
d=edge(d,'canny',.6);
figure,
imshow(d,[])
ds = bwareaopen(d,40);
figure,
imshow(ds,[])
iout = d1;
BW=ds;
iout(:,:,1) = iout;
iout(:,:,2) = iout(:,:,1);
iout(:,:,3) = iout(:,:,1);
iout(:,:,2) = min(iout(:,:,2) + BW, 1.0);
iout(:,:,3) = min(iout(:,:,3) + BW, 1.0);
I understand that d is the image and canny detector is applied and 40 pixels are neglected. The image is gray scale and contour is added to the image.
Can you please explain the next lines? What principle/algorithm is used here? I am having trouble especially with the contour detection portion of the code.
Assuming that the variable d1 stores what is likely a double precision representation (values between 0 and 1) of the original grayscale intensity image that is operated on, then the last 5 lines will turn that grayscale image into a 3-D RGB image iout that looks the same as the original grayscale image except that the contours will be overlaid on the image in cyan.
Here's an example, using the image 'cameraman.tif' that is included with the MATLAB Image Processing Toolbox:
d1 = double(imread('cameraman.tif'))./255; % Load the image, scale from 0 to 1
subplot(2, 2, 1); imshow(d1); title('d1'); % Plot the original image
d = edge(d1, 'canny', .6); % Perform Canny edge detection
subplot(2, 2, 2); imshow(d); title('d'); % Plot the edges
ds = bwareaopen(d, 40); % Remove small edge objects
subplot(2, 2, 3); imshow(ds); title('ds'); % Plot the remaining edges
iout = d1;
BW = ds;
iout(:, :, 1) = iout; % Initialize red color plane
iout(:, :, 2) = iout(:, :, 1); % Initialize green color plane
iout(:, :, 3) = iout(:, :, 1); % Initialize blue color plane
iout(:, :, 2) = min(iout(:, :, 2) + BW, 1.0); % Add edges to green color plane
iout(:, :, 3) = min(iout(:, :, 3) + BW, 1.0); % Add edges to blue color plane
subplot(2, 2, 4); imshow(iout); title('iout'); % Plot the resulting image
And here is the figure the above code creates:
How it works...
The creation of the image iout has nothing to do with the edge detection algorithm. It's simply an easy way to display the edges found in the previous steps. A 2-D grayscale intensity image can't display color, so if you want to add colored contour lines to the image you have to first convert it to a format that will let you show color: either an indexed image (which is a little harder to deal with, in my experience) or a 3-D RGB image (the third dimension represents the red, green, and blue color components of each pixel).
Replicating the grayscale image 3 times in the third dimension gives us a 3-D RGB image that initially still contains gray colors (equal amounts of red, green, and blue per pixel). However, by modifying certain pixels of each color plane we can add color to the image. By adding the logical edge mask BW (ones where edges are and zeroes elsewhere) to the green and blue color planes, those pixels where the contours were found will appear cyan. The call to the function min ensures that the result of adding the images never causes a pixel color value to exceed the value 1.0, which is the maximum value an element should have for a double-precision 3-D RGB image.
It should also be noted that the code for creating the 3-D RGB image can be simplified to the following:
iout = d1;
iout(:, :, 2) = min(d1+ds, 1.0);
iout(:, :, 3) = min(d1+ds, 1.0);