Get contours and points of an image - python

I have my code like this:
import numpy as np
import cv2
im = cv2.imread('snorlax.jpg')
imgray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(imgray, 127, 255, 0)
im2, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
print(contours)
cv2.drawContours(im, contours, -1, (0, 255, 0), 3)
cv2.imshow("imagen", im)
input()
The print show a list of lists that have to number every list I dont know if that are the points (x,y) of the contours and the cv2.show only showme a grey screen and doesn't show me the contours of the image.

import numpy as np
import cv2
img = cv2.imread("snorlax.jpg", cv2.IMREAD_GRAYSCALE)
canny = cv2.Canny(img, 100, 150)
cv2.imshow("Image", img)
cv2.imshow("Canny", canny)
indices = np.where(canny != [0])
coordinates = zip(indices[0], indices[1])
coordinates_list = ""
for coordinate in coordinates:
x = "'('{}, {}')', ".format(coordinate[1] / 100, -coordinate[0] / 100)
coordinates_list += x
coordinates_list = "'('{}')'".format(coordinates_list)
coordinates_list = coordinates_list.replace("'('", "{")
coordinates_list = coordinates_list.replace("')'", "}")
print(coordinates_list)
cv2.waitKey(0)
cv2.destroyAllWindows()
I use canny to resolve the problem then with the "where" function of numpy I get all the white points and zip it in a variable, the last past of the code is to get the points in a specific format to use it in an other language.

Related

What kind of parameters should I use to find and crop objects in an image?

I am new to deep learning and try to implement a ML algorithm for image clustering. The problem is that I can't crop the objects in an image in Python using OpenCV.
Here is the code I have implemented and it works for some objects if the color of the object is very different(in RGB values) from the background but it doesn't work for the image I need for ML algorithm. What kind of parameters should I have/change? Any suggestions?
import cv2
import numpy as np
from PIL import Image
import tkinter as tk
from tkinter import filedialog as fd
from tkinter import*
import random
#!/usr/bin/python
from PIL import Image
import sys
myFile = 'Path' + '/crop.png'
nr_of_im = 1
q = 0
r = 0
x_list = []
y_list = []
img = cv2.imread(myFile, cv2.IMREAD_UNCHANGED)
ret, thresh = cv2.threshold(cv2.cvtColor(img.copy(), cv2.COLOR_BGR2GRAY) , 30, 255, cv2.THRESH_BINARY)
contours, hier = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for contour in contours:
print("len",len(contours))
if cv2.contourArea(contour) > 80:
x, y, w, h = cv2.boundingRect(contour)
q = w
r = h
x_list.append(x)
y_list.append(y)
font = cv2.FONT_HERSHEY_SIMPLEX
ROI = img[y-10:y+10+h, x-10:x+10+w]
ROI = cv2.resize(ROI,(300,300))
file_all = "/images/%d.jpg"%nr_of_im
nr_of_im += 1
cv2.imwrite(file_all,ROI)
There are 21 objects in the image but the length of contours returns 1. The image looks like so
crop.png:
Your threshold is too low and produces a totally white image for me. You need to increase your threshold. Always view your thresholding to be sure it is working the way you expect. You can always remove the viewing later.
The following works for me using Otsu thresholding with a threshold value of 97. I get 21 contours.
Input:
import cv2
import numpy as np
# read image
img = cv2.imread('blocks.jpg')
# convert to grayscale
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# threshold
ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
print(ret)
# apply morphology fill and separate large regions and remove small ones
kernel = cv2.getStructuringElement(cv2.MORPH_RECT , (9,9))
morph = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT , (15,15))
morph = cv2.morphologyEx(morph, cv2.MORPH_OPEN, kernel)
# get contours
result = img.copy()
contours = cv2.findContours(morph, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
# get count of contours
print(len(contours))
# draw bounding boxes on contours
for cntr in contours:
x,y,w,h = cv2.boundingRect(cntr)
cv2.rectangle(result, (x, y), (x+w, y+h), (0, 0, 255), 2)
#print("x,y,w,h:",x,y,w,h)
# save results
cv2.imwrite("blocks_thresh.jpg", thresh)
cv2.imwrite("blocks_morphology.jpg", morph)
cv2.imwrite("blocks_bboxes.jpg", result)
# show thresh and result
cv2.imshow("thresh", thresh)
cv2.imshow("morph", morph)
cv2.imshow("result", result)
cv2.waitKey(0)
cv2.destroyAllWindows()
Threshold image:
Morphology cleaned image:
Resulting bounding boxes from contours:

Segment a region from a numpy array

After some processing of a image I, extracted some region of a image.
Here is the .npy file.
segmented_image = np.load('data.npy')
plt.imshow(segmented_image)
Now, I am trying to crop/segment the region of P. How can I do that ?
Thanks in advance.
You can try contour filtration.
import cv2
import numpy as np
image = np.load("data.npy")
cv2.imshow("image", image)
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
_, threshold_image = cv2.threshold(gray_image, 0, 255, cv2.THRESH_BINARY)
cv2.imshow("threshold_image", threshold_image)
contours, hierarchy = cv2.findContours(threshold_image, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
# here you can apply your conter filter logic
# In this image I can see biggest contur is "p"
selected_contour = max(contours, key=lambda x: cv2.contourArea(x))
mask_image = np.zeros_like(threshold_image)
cv2.drawContours(mask_image, [selected_contour], -1, 255, -1)
cv2.imshow("mask_image", mask_image)
segmented_image = cv2.bitwise_and(image, image, mask=mask_image)
cv2.imshow("segmented_image", segmented_image)
cv2.waitKey(0)

OpenCV, cv2.approxPolyDP() Draws double lines on closed contour

I want to create some polygons out of this mask:
image 1 - Mask
So i created these contours with openCV findcontours():
image 2 - Contours
When creating polygons I get these polygons:
image 3 - Polygons
As you can see some polygons are drawn using double lines. How do I prevent this?
See my code:
import glob
from PIL import Image
import cv2
import numpy as np
# Let's load
image = cv2.imread(path + "BigOneEnhanced.tif")
# Grayscale
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# Find Canny edges
edged = cv2.Canny(gray, 30, 200)
# Finding Contours
contours, hierarchy = cv2.findContours(edged,
cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_TC89_L1)
canvas = np.zeros(image.shape, np.uint8)
# creating polygons from contours
polygonelist = []
for cnt in contours:
# define contour approx
perimeter = cv2.arcLength(cnt,True)
epsilon = 0.005*cv2.arcLength(cnt,True)
approx = cv2.approxPolyDP(cnt,epsilon,True)
polygonelist.append(approx)
cv2.drawContours(canvas, polygonelist, -1, (255, 255, 255), 3)
imgB = Image.fromarray(canvas)
imgB.save(path + "TEST4.png")
The problem source is the Canny edges detection:
After applying edge detection you are getting two contours for every original contour - one outside the edge and one inside the edge (and other weird stuff).
You may solve it by applying findContours without using Canny.
Here is the code:
import glob
from PIL import Image
import cv2
import numpy as np
path = ''
# Let's load
#image = cv2.imread(path + "BigOneEnhanced.tif")
image = cv2.imread("BigOneEnhanced.png")
# Grayscale
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# Apply threshold (just in case gray is not binary image).
ret, thresh_gray = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
# Find Canny edges
#edged = cv2.Canny(gray, 30, 200)
# Finding Contours cv2.CHAIN_APPROX_TC89_L1
#contours, hierarchy = cv2.findContours(edged, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
contours, hierarchy = cv2.findContours(thresh_gray, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
canvas = np.zeros(image.shape, np.uint8)
# creating polygons from contours
polygonelist = []
for cnt in contours:
# define contour approx
perimeter = cv2.arcLength(cnt, True)
epsilon = 0.005*perimeter #0.005*cv2.arcLength(cnt, True)
approx = cv2.approxPolyDP(cnt, epsilon, True)
polygonelist.append(approx)
cv2.drawContours(canvas, polygonelist, -1, (255, 255, 255), 3)
imgB = Image.fromarray(canvas)
imgB.save(path + "TEST4.png")
Result:

How to remove blurriness in an image that contains table?

I have an image that is blurred and contains some noise. I have tried Image Denoising from the following example.
The code to remove the Gaussian noise from a color image using the Non-local Means Denoising algorithm:
import numpy as np
import cv2
from matplotlib import pyplot as plt
img = cv2.imread("data_5/1.png")
b,g,r = cv2.split(img) # get b,g,r
rgb_img = cv2.merge([r,g,b]) # switch it to rgb
# Denoising
dst = cv2.fastNlMeansDenoisingColored(img,None,10,10,7,21)
b,g,r = cv2.split(dst) # get b,g,r
rgb_dst = cv2.merge([r,g,b]) # switch it to rgb
cv2.imshow('denoising black and white', rgb_dst)
cv2.waitKey(0)
The output of the above code:
The above code removes some noise. But here some numbers are blurred and the table lines are blurred.
Can anyone suggest me a better solution to remove blurriness and Noise from the above image?
import numpy as np
import cv2
from PIL import Image
from tesserocr import PyTessBaseAPI, RIL
if __name__ == '__main__':
image = cv2.imread('image.png',cv2.IMREAD_UNCHANGED)
image = cv2.resize(image, (0,0), fx=0.5, fy=0.5)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
ret,binary = cv2.threshold(gray, 0, 255, cv2.THRESH_OTSU | cv2.THRESH_BINARY_INV)
binary = cv2.medianBlur(binary, 3)
(rows,cols) = image.shape[:2]
H = cv2.Sobel(binary, cv2.CV_8U, 1, 0, ksize = 5)
V = cv2.Sobel(binary, cv2.CV_8U, 0, 1, ksize = 5)
_,contours,_ = cv2.findContours(V, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
for cnt in contours:
(x,y,w,h) = cv2.boundingRect(cnt)
if w < cols/3 and h < rows/3:
cv2.drawContours(V, [cnt], -1, 0, -1)
_,contours,_ = cv2.findContours(H, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
for cnt in contours:
(x,y,w,h) = cv2.boundingRect(cnt)
if w < cols/3 and h < rows/3:
cv2.drawContours(H, [cnt], -1, 0, -1)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3))
V = cv2.morphologyEx(V, cv2.MORPH_DILATE, kernel, iterations = 3)
H = cv2.morphologyEx(H, cv2.MORPH_DILATE, kernel, iterations = 3)
binary[V == 255] = 0
binary[H == 255] = 0
binary = cv2.bitwise_not(binary)
api = PyTessBaseAPI()
api.SetImage(Image.fromarray(binary))
text = api.GetUTF8Text()
text = text.split()
boxes = api.GetComponentImages(RIL.TEXTLINE, True)
for i, (_, box, _, _) in enumerate(boxes):
(x,y,w,h) = box['x'], box['y'], box['w'], box['h']
cv2.rectangle(image, (x,y), (x+w,y+h), (0,0,255))
cv2.putText(image, text[i], (x,y), cv2.FONT_HERSHEY_PLAIN, 1, (255,0,0))
cv2.imshow('image', image)
cv2.waitKey(0)
cv2.destroyAllWindows()
I have tried applying a Gaussian Blur then processing it with adaptive thresholding and result removed noise in the image and blurriness.
import cv2 as cv
#input
img = cv.imread('data_5/1.png',0)
#gaussian Blur
img = cv.GaussianBlur(img, (15,15),0)
#adaptive threshold
th3 = cv.adaptiveThreshold(img,255,cv.ADAPTIVE_THRESH_GAUSSIAN_C,\
cv.THRESH_BINARY,11,2)
cv2.imshow('Noise Filtered Image', th3)
cv2.waitKey(0)
cv.imwrite('data_5/result.png',th3)
The output of the above code:
Can anyone help me to smoothen this image? I want an output quality similar to this table below. Removal of table lines is ok.
My goal is to have an image with clear text.

Labelling the contours with numbers and then extracting the coordinates of any numbered contour

I need to label each contour with numbers so that with the help of following code i can extract the coordinates of that particular contour.
Here is the image:
import numpy as np
import cv2
THRESHOLD = 55
CONTOUR = 55
im = cv2.imread("ceramic.bmp")
imgray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(imgray,THRESHOLD,255,0)
_th,contours, hierarchy =
cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
print "Number of contours detected = %d" % len(contours)
cv2.drawContours(im,contours,CONTOUR,(1,70,255))
area = cv2.contourArea(contours[CONTOUR])
print (area)
cv2.imshow("Contours",im)
np.set_printoptions(threshold=np.inf)
coords = np.array2string(contours[CONTOUR])
open("contour_%d.txt" % CONTOUR, "w").write(coords)
cv2.waitKey(0)
cv2.destroyAllWindows()`
There are couple of things to mention in your code:
Firstly, when you want to find contours the shape must be in white. The image provided by you has shapes that are dark. So I had to invert your image and then find the contours.
Secondly, you were storing coordinates of only one contour. I have modified your code to store coordinates for each contour in a separate file.
Code:
import numpy as np
import cv2
THRESHOLD = 55
path = 'C:/Users/Desktop/'
im = cv2.imread(path + 'date.jpg')
imgray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
cv2.imshow("imgray", imgray)
ret, thresh = cv2.threshold(imgray, THRESHOLD, 255, 0)
cv2.imshow('thresh', thresh)
_th, contours, hierarchy = cv2.findContours(cv2.bitwise_not(thresh), cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
print "Number of contours detected = %d" % len(contours)
cv2.drawContours(im, contours, -1, (1, 70, 255), 2)
cv2.imshow("Contours", im)
contour_num = 0
for i in range(0, len(contours)):
coords = np.array2string(contours[i])
contour_num+=1
open(path + 'contour_%d.txt' %contour_num, "w").write(coords)
cv2.waitKey(0)
cv2.destroyAllWindows()
Run the code as it is and see the saved files.

Categories

Resources