Automatic Scaling when the image is resize - python

I am having a problem when I change the size of the image. Then the proportions of the line no longer match those of the image, i.e. the line will become smaller than expected.
Any idea how I can resize the line proportionally equal to the image?
Here is the original image:
Here is the result that I want:
But this is the result that I get after resizing (it gives the same value at second picture):
from scipy.spatial import distance as dist
from imutils import perspective
from imutils import contours
import numpy as np
import imutils
import cv2
# Method to find the mid point
def midpoint(ptA, ptB):
return ((ptA[0] + ptB[0]) * 0.5, (ptA[1] + ptB[1]) * 0.5)
img = cv2.imread('banana4.jpg')
# Gaussian blur
blur1 = cv2.GaussianBlur(img,(3,3),1)
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
lower_blue = np.array([5, 25, 25])
upper_blue = np.array([70, 255, 255])
thresh = cv2.inRange(hsv, lower_blue, upper_blue)
# Find contours and sort for largest contour
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
cnts = sorted(cnts, key=cv2.contourArea, reverse=True)
for c in cnts:
x, y, w, h = cv2.boundingRect(c)
box = cv2.minAreaRect(c)
box = cv2.cv.BoxPoints(box) if imutils.is_cv2() else cv2.boxPoints(box)
box = np.array(box, dtype="int")
box = perspective.order_points(box)
orig = img.copy()
cv2.drawContours(orig, [box.astype("int")], -1, (0, 255, 0), 3)
(tl, tr, br, bl) = box
(tltrX, tltrY) = midpoint(tl, tr)
(blbrX, blbrY) = midpoint(bl, br)
(tlblX, tlblY) = midpoint(tl, bl)
(trbrX, trbrY) = midpoint(tr, br)
# draw and write the midpoints on the image
cv2.circle(orig, (int(tltrX), int(tltrY)), 5, (255, 0, 0), -1)
cv2.putText(orig, "({},{})".format(tltrX, tltrY), (int(tltrX - 50), int(tltrY - 10) - 20),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255,0,0), 2)
cv2.circle(orig, (int(blbrX), int(blbrY-90)), 5, (255, 0, 0), -1)
cv2.putText(orig, "({},{})".format(blbrX, blbrY-90), (int(blbrX - 50), int(blbrY - 10) - 20),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255,0,0), 2)
# draw lines between the midpoints
cv2.line(orig, (int(tltrX), int(tltrY)), (int(blbrX), int(blbrY-90)),
(255, 0, 255), 2)
# compute the Euclidean distance between the midpoints
dA = dist.euclidean((tltrX, tltrY), (blbrX, blbrY))
dB = dist.euclidean((tlblX, tlblY), (trbrX, trbrY))
cv2.imshow("Image", orig)
break

Related

How do I differentiate individual objects in an image, when they are clustered together and calculate object size

I'm currently trying to measure the size of woodchips within an image using openCV and a reference object(the coin)
(https://i.stack.imgur.com/GpdJE.jpg).
It mostly works but when the woodchips are close to one another find countours recognizes it as one larger contour. I recently read about the watershed algorithm which can be used to segment the objects more efficiently. However how do I implementent it and simulatanously calculate the height and with of each object relative to the reference object?
Here is my code for measuring the woodchip size
# Read image and preprocess (read an image and convert it it no grayscale)
image = cv2.imread(img_path)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255,
cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
#Blur the image using Gaussian Kernel to remove un-necessary edges
#blur = cv2.GaussianBlur(gray, (9, 9), 0)
#blur = cv2.medianBlur(gray, 7)
blur = cv2.bilateralFilter(thresh,11, 125, 125)
#nbw = cv2.fastNlMeansDenoising(image, None, 10, 7, 21)
#Edge detection using Canny edge detector
edged = cv2.Canny(blur, 50, 100)
edged = cv2.dilate(edged, None, iterations=2)
edged = cv2.erode(edged, None, iterations=2)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (6,6))
closing = cv2.morphologyEx(edged, cv2.MORPH_CLOSE, kernel)
#show_images([blur, edged])
# Find contours
cnts = cv2.findContours(closing.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
# Sort contours from left to right as leftmost contour is reference object
(cnts, _) = contours.sort_contours(cnts)
# Remove contours which are not large enough , Perform morphological closing operation to remove noisy contours
cnts = [x for x in cnts if cv2.contourArea(x) > 400]
# Reference object dimensions
# Here for reference I have used a 2cm x 2cm square
ref_object = cnts[0]
box = cv2.minAreaRect(ref_object)
box = cv2.boxPoints(box)
box = np.array(box, dtype="int")
box = perspective.order_points(box)
(tl, tr, br, bl) = box
dist_in_pixel = euclidean(tl, tr)
dist_in_cm = 2
pixel_per_cm = dist_in_pixel/dist_in_cm
# Draw remaining contours
measurement=[]
for cnt in cnts:
box = cv2.minAreaRect(cnt)
box = cv2.boxPoints(box)
box = np.array(box, dtype="int")
box = perspective.order_points(box)
(tl, tr, br, bl) = box
cv2.drawContours(image, [box.astype("int")], -1, (0, 0, 255), 2)
mid_pt_horizontal = (tl[0] + int(abs(tr[0] - tl[0])/2), tl[1] + int(abs(tr[1] - tl[1])/2))
mid_pt_verticle = (tr[0] + int(abs(tr[0] - br[0])/2), tr[1] + int(abs(tr[1] - br[1])/2))
wid = euclidean(tl, tr)/pixel_per_cm
ht = euclidean(tr, br)/pixel_per_cm
measurement.append((wid,ht))
cv2.putText(image, "{:.1f}cm".format(wid), (int(mid_pt_horizontal[0] - 15), int(mid_pt_horizontal[1] - 10)),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 0), 2)
cv2.putText(image, "{:.1f}cm".format(ht), (int(mid_pt_verticle[0] + 10), int(mid_pt_verticle[1])),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 0), 2)
cv2_imshow(image)
cv2.waitKey(0)
cv2.destroyAllWindows()
Result:
(https://i.stack.imgur.com/nmaW3.jpg)

Video/image analysis to acquire distances between contours

New image: test image
I'm trying to quantify the distance between two contours in a video of a microvessel (see snapshot)
Image analysis structure
Right now I'm only able to select for one contour (which is outlined) and I'm acquiring dimensions from this outline, but what I'd like to select for is the top and bottom contour of the structure and measure the distance (labeled with an orange line and A in the snapshot).
Any suggestions as to do this? My code for this video analysis is the following. Thanks for the help in advance!:
import cv2
import pandas as pd
import numpy as np
import imutils
from scipy.spatial import distance as dist
from imutils import perspective
from imutils import contours
videocapture = cv2.VideoCapture('RTMLV.mp4')
def safe_div(x,y):
if y==0: return 0
return x/y
def nothing(x):
pass
def rescale_frame(frame, percent=100): #make the video windows a bit smaller
width = int(frame.shape[1]*percent/100)
height = int(frame.shape[0]*percent/100)
dim = (width, height)
return cv2.resize(frame, dim, interpolation=cv2.INTER_AREA)
if not videocapture.isOpened():
print("Unable to open video")
exit()
windowName="Vessel Tracking"
cv2.namedWindow(windowName)
# Sliders to adjust image
cv2.createTrackbar("Threshold", windowName, 75, 255, nothing)
cv2.createTrackbar("Kernel", windowName, 5, 30, nothing)
cv2.createTrackbar("Iterations", windowName, 1, 10, nothing)
showLive=True
while(showLive):
ret, frame=videocapture.read()
frame_resize=rescale_frame(frame)
if not ret:
print("Cannot capture the frame")
exit()
thresh = cv2.getTrackbarPos("Threshold", windowName)
ret,thresh1 = cv2.threshold(frame_resize, thresh, 255, cv2.THRESH_BINARY)
kern = cv2.getTrackbarPos("Kernel", windowName)
kernel = np.ones((kern, kern), np.uint8) # square image kernel used for erosion
itera=cv2.getTrackbarPos("Iterations", windowName)
dilation = cv2.dilate(thresh1, kernel, iterations=itera)
erosion = cv2.erode(dilation, kernel, iterations=itera) #refines all edges in the binary image
opening = cv2.morphologyEx(erosion, cv2.MORPH_OPEN, kernel)
closing = cv2.morphologyEx(opening, cv2.MORPH_CLOSE, kernel)
closing = cv2.cvtColor(closing, cv2.COLOR_BGR2GRAY)
contours,hierarchy = cv2.findContours(closing,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE) # find contours with simple approximation cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE
closing = cv2.cvtColor(closing,cv2.COLOR_GRAY2RGB)
cv2.drawContours(closing, contours, -1, (128,255,0), 1)
# focus on only the largest outline by area
areas = [] #list to hold all areas
for contour in contours:
ar = cv2.contourArea(contour)
areas.append(ar)
max_area = max(areas)
max_area_index = areas.index(max_area) # index of the list element with largest area
cnt = contours[max_area_index - 1] # largest area contour is usually the viewing window itself, why?
cv2.drawContours(closing, [cnt], 0, (0,0,255), 1)
def midpoint(ptA, ptB):
return ((ptA[0] + ptB[0]) * 0.5, (ptA[1] + ptB[1]) * 0.5)
# compute the rotated bounding box of the contour
orig = frame_resize.copy()
box = cv2.minAreaRect(cnt)
box = cv2.cv.BoxPoints(box) if imutils.is_cv2() else cv2.boxPoints(box)
box = np.array(box, dtype="int")
# order the points in the contour such that they appear
# in top-left, top-right, bottom-right, and bottom-left
# order, then draw the outline of the rotated bounding
# box
box = perspective.order_points(box)
cv2.drawContours(orig, [box.astype("int")], -1, (0, 255, 0), 1)
# loop over the original points and draw them
for (x, y) in box:
cv2.circle(orig, (int(x), int(y)), 5, (0, 0, 255), -1)
# unpack the ordered bounding box, then compute the midpoint
# between the top-left and top-right coordinates, followed by
# the midpoint between bottom-left and bottom-right coordinates
(tl, tr, br, bl) = box
(tltrX, tltrY) = midpoint(tl, tr)
(blbrX, blbrY) = midpoint(bl, br)
# compute the midpoint between the top-left and top-right points,
# followed by the midpoint between the top-right and bottom-right
(tlblX, tlblY) = midpoint(tl, bl)
(trbrX, trbrY) = midpoint(tr, br)
# draw the midpoints on the image
cv2.circle(orig, (int(tltrX), int(tltrY)), 5, (255, 0, 0), -1)
cv2.circle(orig, (int(blbrX), int(blbrY)), 5, (255, 0, 0), -1)
cv2.circle(orig, (int(tlblX), int(tlblY)), 5, (255, 0, 0), -1)
cv2.circle(orig, (int(trbrX), int(trbrY)), 5, (255, 0, 0), -1)
# draw lines between the midpoints
cv2.line(orig, (int(tltrX), int(tltrY)), (int(blbrX), int(blbrY)),(255, 0, 255), 1)
cv2.line(orig, (int(tlblX), int(tlblY)), (int(trbrX), int(trbrY)),(255, 0, 255), 1)
cv2.drawContours(orig, [cnt], 0, (0,0,255), 1)
# compute the Euclidean distance between the midpoints
dA = dist.euclidean((tltrX, tltrY), (blbrX, blbrY))
dB = dist.euclidean((tlblX, tlblY), (trbrX, trbrY))
# compute the size of the object
P2M4x = 1.2
P2M10x = 3.2
P2M20x = 6
pixelsPerMetric = P2M10x # Pixel to micron conversion
dimA = dA / pixelsPerMetric
dimB = dB / pixelsPerMetric
dimensions = [dimA, dimB]
# draw the object sizes on the image
cv2.putText(orig, "{:.1f}um".format(dimA), (int(tltrX - 15), int(tltrY - 10)), cv2.FONT_HERSHEY_SIMPLEX, 0.65, (255, 255, 255), 2)
cv2.putText(orig, "{:.1f}um".format(dimB), (int(trbrX + 10), int(trbrY)), cv2.FONT_HERSHEY_SIMPLEX, 0.65, (255, 255, 255), 2)
# compute the center of the contour
M = cv2.moments(cnt)
cX = int(safe_div(M["m10"],M["m00"]))
cY = int(safe_div(M["m01"],M["m00"]))
# draw the contour and center of the shape on the image
cv2.circle(orig, (cX, cY), 5, (255, 255, 255), -1)
cv2.putText(orig, "center", (cX - 20, cY - 20), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 2)
cv2.imshow(windowName, orig)
cv2.imshow('', closing)
if cv2.waitKey(30)>=0:
showLive=False
videocapture.release()
cv2.destroyAllWindows()
Edits have been made to this answer in reponse to the new test image that was added to the post.
I was unable to segment the blood vessel in the test image using the code that you uploaded. I segmented the image by using manual annotation and the GrabCut algorithm.
This is the code that I used for the manual segmentation:
import cv2, os, numpy as np
import time
# Plot with Matplotlib
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
img_path = '/home/stephen/Desktop/0lszR.jpg'
img = cv2.imread(img_path)
img = img[420:1200, :]
h,w,_ = img.shape
mask = np.zeros((h,w), np.uint8)
mask[:] = 2
src = img.copy()
h,w,_ = img.shape
drawing = src.copy()
# Mouse callback function
global k, px, py
k = 0
px, py = 0,0
def callback(event, x, y, flags, param):
global k, px, py
print(x,y, k, px, py)
if k == 115: # 's' for sure background
if px+py!=0:
cv2.line(img, (x,y), (px, py), (255,255,0), 8)
cv2.line(mask, (x,y), (px, py), 0, 8)
if k == 116: # 't' for sure foreground
if px+py!=0:
cv2.line(img, (x,y), (px, py), (0,255,255), 8)
cv2.line(mask, (x,y), (px, py), 1, 8)
else: print(px, py)
px, py = x,y
#if k != 115 or 116: px, py = 0,0
cv2.namedWindow('img')
cv2.setMouseCallback('img', callback)
while k != 27:
cv2.imshow('img', img)
k_temp = cv2.waitKey(1)
if k_temp!=-1: k = k_temp
cv2.destroyAllWindows()
After I had found the segmented image, I used the function np.nonzero() to find the tops and bottoms of the columns:
This is the code that I used to find the width:
# Initialize parameters for the GrabCut algorithm
bgdModel = np.zeros((1,65),np.float64)
fgdModel = np.zeros((1,65),np.float64)
# Apply GrabCut
out_mask = mask.copy()
out_mask, _, _ = cv2.grabCut(src,out_mask,None,bgdModel,fgdModel,1,cv2.GC_INIT_WITH_MASK)
out_mask = np.where((out_mask==2)|(out_mask==0),0,1).astype('uint8')
# Open the mask to fill in the holes
out_img = src*out_mask[:,:,np.newaxis]
flip_mask = cv2.flip(out_mask, 0)
# Find the distances
distances = []
for col_num in range(src.shape[1]-1):
col = out_mask[:, col_num:col_num+1]
flip_col = flip_mask[:, col_num:col_num+1]
top = np.nonzero(col)[0][0]
bottom = h-np.nonzero(flip_col)[0][0]
if col_num % 12 == 0:
cv2.line(drawing, (col_num, top), (col_num, bottom), (234,345,34), 4)
distances.append(bottom-top)
f, axarr = plt.subplots(2,3, sharex=True)
axarr[0,0].imshow(src)
axarr[0,1].imshow(out_mask)
axarr[0,2].imshow(drawing)
axarr[1,0].imshow(img)
axarr[1,1].imshow(out_img)
axarr[1,2].plot(distances)
axarr[0,0].set_title("Source")
axarr[0,1].set_title('Mask from GrabCut')
axarr[0,2].set_title('Widths')
axarr[1,0].set_title('Manual Annotation')
axarr[1,1].set_title('GrabCut Mask')
axarr[1,2].set_title('Graph of Width')
axarr[0,0].axis('off')
axarr[0,1].axis('off')
axarr[1,0].axis('off')
axarr[1,1].axis('off')
axarr[1,2].axis('off')
axarr[0,2].axis('off')
plt.show()

How to avoid grouping images (bars) while selecting contours in an image?

I am extracting the length of individual bars from a chart image. It works fine in most of the cases but in some cases the contour groups 2 bars as 1 which is detrimental to my cause. I tried different combinations of canny,dilate, erode, and color scheme. It improved the result only slightly. How can avoid the grouping? Here is the complete code and one image. You can run using this image too see the problem.
from scipy.spatial import distance as dist
from imutils import perspective
from imutils import contours
import numpy as np
import argparse
import imutils
import cv2
def midpoint(ptA, ptB):
return ((ptA[0] + ptB[0]) * 0.5, (ptA[1] + ptB[1]) * 0.5)
image = cv2.imread("somefile.png")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (7, 7), 0)
#edged=cv2.Laplacian(gray, cv2.CV_8U, gray, ksize=7)
edged = cv2.Canny(gray, 30, 50)
cv2.imwrite("test00.png", edged)
edged = cv2.dilate(edged, None, iterations=1)
cv2.imwrite("test01.png", edged)
edged = cv2.erode(edged, None, iterations=1)
cv2.imwrite("test02.png", edged)
cnts = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
pixelsPerMetric = 100
for c in cnts:
orig = image.copy()
box = cv2.minAreaRect(c)
box = cv2.cv.BoxPoints(box) if imutils.is_cv2() else cv2.boxPoints(box)
box = np.array(box, dtype="int")
print(box)
box = perspective.order_points(box)
cv2.drawContours(orig, [box.astype("int")], -1, (0, 255, 0), 2)
for (x, y) in box:
cv2.circle(orig, (int(x), int(y)), 5, (0, 0, 255), -1)
(tl, tr, br, bl) = box
(tltrX, tltrY) = midpoint(tl, tr)
(blbrX, blbrY) = midpoint(bl, br)
(tlblX, tlblY) = midpoint(tl, bl)
(trbrX, trbrY) = midpoint(tr, br)
cv2.circle(orig, (int(tltrX), int(tltrY)), 5, (255, 0, 0), -1)
cv2.circle(orig, (int(blbrX), int(blbrY)), 5, (255, 0, 0), -1)
cv2.circle(orig, (int(tlblX), int(tlblY)), 5, (255, 0, 0), -1)
cv2.circle(orig, (int(trbrX), int(trbrY)), 5, (255, 0, 0), -1)
cv2.line(orig, (int(tltrX), int(tltrY)), (int(blbrX), int(blbrY)),
(255, 0, 255), 2)
cv2.line(orig, (int(tlblX), int(tlblY)), (int(trbrX), int(trbrY)),
(255, 0, 255), 2)
dA = dist.euclidean((tltrX, tltrY), (blbrX, blbrY))
dB = dist.euclidean((tlblX, tlblY), (trbrX, trbrY))
dimA = dA / pixelsPerMetric
dimB = dB / pixelsPerMetric
cv2.putText(orig, "{:.1f}in".format(dimA),
(int(tltrX - 15), int(tltrY - 10)), cv2.FONT_HERSHEY_SIMPLEX,
0.65, (255, 255, 255), 2)
cv2.putText(orig, "{:.1f}in".format(dimB),
(int(trbrX + 10), int(trbrY)), cv2.FONT_HERSHEY_SIMPLEX,
0.65, (255, 255, 255), 2)
cv2.imshow("Image", orig)
cv2.waitKey(0)
This image is trivial to segment. The color of the bars is exactly RGB=(245,222,179). You can use OpenCV's function inRange to find pixels of this color. In this function, we need to give the color in BGR order, because that is how OpenCV reads in images by default. Here I'm picking a slightly larger range in case the image used JPEG compression (which is lossy and therefore changes pixel values slightly):
image = cv2.imread("somefile.png")
mask = cv2.inRange(image, (177, 220, 243), (181, 224, 247))
This image mask now has perfectly separated bars:

Detect lines with dark color and end lines using Hough Tranform

i'm trying to detect vertical lines where the pixels RGB has every color in less than 100 |Dark| , here is an example RGB (100,100,100).
import numpy as np
import cv2
img = cv2.imread('testD2.png')
lower = np.array([0, 0, 0], dtype = "uint8")
upper = np.array([100,100,100], dtype = "uint8")
mask = cv2.inRange(img, lower, upper)
img = cv2.bitwise_and(img, img, mask = mask)
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray,50,150,apertureSize = 3)
minLineLength=img.shape[1]-300
lines = cv2.HoughLinesP(image=edges,rho=0.02,theta=np.pi/500, threshold=10,lines=np.array([]), minLineLength=minLineLength,maxLineGap=100)
if lines is not None:
a,b,c = lines.shape
for i in range(a):
cv2.line(img, (lines[i][0][0], lines[i][0][1]), (lines[i][0][2], lines[i][0][3]), (0, 0, 255), 3, cv2.LINE_AA)
cv2.imshow('edges', edges)
cv2.imshow('result', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
i have to change the color of the end lines too,i mean the first and the last line.
Using cv2.findContours() may work better:
You can use cv2.findContours() and cv2.boundingRect() to identify the bars and return the information (x,y,h,w) that describes these rectangles. Here are a few examples.
If you want to only identify the lines and mark them you can do:
import cv2
import numpy as np
img = cv2.imread('oVKlP.png')
g = cv2.imread('oVKlP.png',0)
(T, mask) = cv2.threshold(g, 100, 255, cv2.THRESH_BINARY_INV)
_, contours, hierarchy = cv2.findContours(mask.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
img = cv2.drawContours(img.copy(), contours, -1, (0,255,0), 2)
cv2.imwrite('just_contours.png',img)
Result:
If you want to display some of the line info like maybe the x value for a side of the bar you can do:
import cv2
import numpy as np
img = cv2.imread('oVKlP.png')
g = cv2.imread('oVKlP.png',0)
(T, mask) = cv2.threshold(g, 100, 255, cv2.THRESH_BINARY_INV)
_, contours, hierarchy = cv2.findContours(mask.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# bounds with x,y,h,w for each bar
bounds = [cv2.boundingRect(i) for i in contours]
bounds.reverse()
img = cv2.drawContours(img.copy(), contours, -1, (0,0,255), 2)
font = cv2.FONT_HERSHEY_SIMPLEX
n = 20
b = 0
for (x,y,w,h) in bounds:
cv2.circle(img, (x,y+n+10), 5, (0, 255, 0), -1, cv2.LINE_AA)
cv2.putText(img, '{0}'.format(x), (x-b, y+n), font, .6, (255, 0, 255), 2, cv2.LINE_AA)
n+=33
b+=3
cv2.imwrite('fancy_marks.png',img)
Result:

How to detect shape in Cytologique image python opencv

I try to detect forms in cytology image and I get this result enter image description here my input image is enter image description here But My result does not see good can anyone help me ???
My stage was,
Color image by (COLORMAP_HOT)
Convert to grayscal image
Apply the canny filter
Find count
Test the contour
and i use python3.5 and opencv3
my code :
#!/usr/bin/env python
import cv2
import numpy as np
from pyimagesearch.shapedetector import ShapeDetector
import argparse
import imutils
from scipy import ndimage
import math
import matplotlib.pyplot as plt
if __name__ == '__main__' :
im = cv2.imread("23.png")
#im_out = np.zeros((670, 543, 3), np.uint8);
#resized = imutils.resize(im, width=300)
#ratio = im.shape[0] / float(resized.shape[0])
#coloration
im_color = cv2.applyColorMap(im, cv2.COLORMAP_HOT)
imgg = im_color[:, :, 1]
#cv2.putText(im_color, colormap_name(k), (30, 180), cv2.FONT_HERSHEY_DUPLEX, 0.5, (255, 255, 255),1);
im_out = im_color
gray = cv2.cvtColor(im_color, cv2.COLOR_RGB2GRAY)
blurred = cv2.GaussianBlur(gray, (3, 3), 0)
canny = cv2.Canny(blurred, 120, 200)
kernel = np.ones((5,5),np.uint8)
#morph
dilation = cv2.dilate(canny,kernel,iterations = 1)
erosion = cv2.erode(dilation,kernel,iterations = 1)
dilation = cv2.dilate(erosion,kernel,iterations = 1)
erosion = cv2.erode(dilation,kernel,iterations = 1)
blurred = cv2.GaussianBlur(erosion, (3, 3), 0)
canny = cv2.Canny(blurred, 200, 200)
cv2.imshow("dilation", dilation)
cv2.imshow("canny", canny)
cv2.imshow("erosion", erosion)
#(thresh, im_bw) = cv2.threshold(im_gray, 128, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
cv2.imshow("im_out", im_out);
cv2.imshow("gray ", gray);
#contour
cnts = cv2.findContours(canny, cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if imutils.is_cv2() else cnts[1]
# loop over the contours
for c in cnts:
M = cv2.moments(c)
if(M["m00"]==0):M["m00"]=1
cX = int((M["m10"] / M["m00"]))
cY = int((M["m01"] / M["m00"]))
#shape = detect(c)
c = c.astype("float")
c = c.astype("int")
#cv2.drawContours(im, [c], -1, (0, 255, 0), 2)
#cv2.putText(im, shape, (cX, cY), cv2.FONT_HERSHEY_SIMPLEX,0.5, (255,0,0), 2)
area = cv2.contourArea(c)
perimeter = cv2.arcLength(c,True)
M = cv2.moments(c)
# initialize the shape name and approximate the contour
shape = " "
peri = cv2.arcLength(c, True)
approx = cv2.approxPolyDP(c, 0.05 * peri, True)
(x, y, w, h) = cv2.boundingRect(approx)
area = cv2.contourArea(c)
radius = w/2
if len(approx) == 3:
shape = ""
# if the shape has 4 vertices, it is either a square or
# a rectangle
elif len(approx) == 4:
if (M['m00']==0):
M['m00']=1
cx = int(M['m10']/M['m00'])
cy = int(M['m01']/M['m00'])
# compute the bounding box of the contour and use the
# bounding box to compute the aspect ratio
#(x,y) be the top-left coordinate of the rectangle and (w,h) be its width and height.
(x, y, w, h) = cv2.boundingRect(approx)
print ("area",area,"perimeter",perimeter,"cx",cx,"cy",cy,"x",x,"y", y,"w", w, "h",h)
#fichier.write("area",area,"perimeter",perimeter,"cx",cx,"cy",cy)
print (sep="\n")
ar = w / float(h)
shape = "square" if ar >= 0.95 and ar <= 1.05 else "rectangle"
cv2.drawContours(im, [c], -1, (255, 0, 0), 2)
cv2.putText(im, shape, (cX, cY), cv2.FONT_HERSHEY_SIMPLEX,0.5, (255,0,0), 2)
# if Cystine>6
elif len(approx) == 6:
if (M['m00']==0):
M['m00']=1
cx = int(M['m10']/M['m00'])
cy = int(M['m01']/M['m00'])
print ("area",area,"perimeter",perimeter,"cx",cx,"cy",cy)
print (sep="\n")
shape = "HEXA"
cv2.drawContours(im, [c], -1, (255, 0, 0), 2)
cv2.putText(im, shape, (cX, cY), cv2.FONT_HERSHEY_SIMPLEX,0.5, (255,0,0), 2)
# otherwise, we assume the shape is a circle
elif (abs(1 - (float(w)/h))<=2 and abs(1-(area/(math.pi*radius*radius)))<=0.2):
if (M['m00']==0):
M['m00']=1
cx = int(M['m10']/M['m00'])
cy = int(M['m01']/M['m00'])
print ("area",area,"perimeter",perimeter,"cx",cx,"cy",cy)
print (sep="\n")
shape = "circle"
cv2.drawContours(im, [c], -1, (255,0, 0), 2)
cv2.putText(im, shape, (cX, cY), cv2.FONT_HERSHEY_SIMPLEX,0.5, (255,0, 0), 2)
# show the output image
cv2.imshow("Image", im)
cv2.waitKey(0);

Categories