0

I want to detect form with opencv and python so i chose Contour Features but now i have problem how can i distinguish between a square and a lozenge using opencv and python if there is other method can you tell me please my image it like this :enter image description here i add my code

#-*- coding: utf-8 -*-

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
from skimage import io, morphology, img_as_bool, segmentation
global limit
 # cv2.threshold(src, thresh, maxval, type[, dst])

import math
def angle(pt1, pt2):
    x1, y1 = pt1
    x2, y2 = pt2
    inner_product = x1*x2 + y1*y2
    len1 = math.hypot(x1, y1)
    len2 = math.hypot(x2, y2)
    return math.acos(inner_product/(len1*len2))

def calculate(pt, ls):
    i = 2
    for x in ls:
        pt2 = (x, i)
        i = i+1
        ang = angle(pt, pt2)*180/math.pi
        ang = ang * (-1)
        print (ang)
Image = cv2.imread("114.png")

# Extraction of Blue channel
b = Image[:,:,0]

# Callback Function for Trackbar (but do not any work)
def nothing(*arg):
    pass

 # Generate trackbar Window Name
TrackbarName = "Trackbar"

 # Make Window and Trackbar
cv2.namedWindow("window", cv2.WINDOW_NORMAL)
cv2.createTrackbar(TrackbarName, "window", 0, 250, nothing)

img_threshed = np.zeros(b.shape, np.uint8)



ret,img_threshed = cv2.threshold(b,168,255,cv2.THRESH_BINARY)
cv2.imshow("window55", img_threshed)
# Expanding borders of the objects
kernel = np.ones((9, 9),np.uint8)
img_dilated = cv2.dilate(img_threshed, kernel)
cv2.namedWindow("Dilated Blue Channel", cv2.WINDOW_NORMAL)
cv2.imshow("Dilated Blue Channel", img_dilated)


# Retrieving contours by subtraction base objects from the expanded objects
img_contours = img_dilated - img_threshed
cv2.namedWindow("Contours", cv2.WINDOW_NORMAL)
cv2.imshow("Contours", img_contours)

median = cv2.medianBlur(img_contours,3)
cv2.imshow("median img_threshed", median)
#_, contours0, hierarchy = cv2.findContours( median, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
#cnts = [cv2.approxPolyDP(cnt, 2, True) for cnt in contours0]



gray = cv2.imread('114.png')
    #gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (3, 3), 0)

    # apply Canny edge detection using a wide threshold, tight
    # threshold, and automatically determined threshold
wide = cv2.Canny(blurred, 90, 150)
cnts = cv2.findContours(img_contours, cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)

#----Find contour in the image----
_, contours, hierarchy = cv2.findContours(img_contours, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)




cnts = cnts[0] if imutils.is_cv2() else cnts[1]
    # loop over the contours
for c in cnts:



        #----Draw a rectangle having minimum area around it using Contour features as you mentioned----
        rect = cv2.minAreaRect(c)  #---I used cnt[0] since there is only one contour in the image----
        box = cv2.boxPoints(rect)
        box = np.int0(box)
        im = cv2.drawContours(Image, [box], 0, (0,0,255), 2)

        #----Draw one diagonal ----
        #cv2.line(Image,(box[2][0],box[2][1]),(box[0][0],box[0][1]), (255,0,0),2)
        #cv2.line(Image,(0,10),(Image.shape[1], 10), (255,255,0),2)
        #calculate(cv2.line(Image,(box[2][0],box[2][1]),(box[0][0],box[0][1]), (255,0,0),2),cv2.line(Image,(0,10),(Image.shape[1], 10), (255,255,0),2))


cv2.imwrite("Final_Image.jpg", Image)
    # show the output image
cv2.imshow("Image", Image)
cv2.waitKey(0)

cv2.destroyAllWindows()
Zahra
  • 369
  • 1
  • 2
  • 9

1 Answers1

0

As mentioned in the comments' section, if you want to distinguish between an apparent square from a lozenge the only property that is distinct are the diagonals.

Using python in OpenCV I coded the following to obtain 1 diagonal for the square and the lozenge:

#----Find contour in the image----
_, contours, hierarchy = cv2.findContours(th, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

#----Draw a rectangle having minimum area around it using Contour features as you mentioned----
rect = cv2.minAreaRect(cnt[0])  #---I used cnt[0] since there is only one contour in the image----
box = cv2.boxPoints(rect)
box = np.int0(box)
im = cv2.drawContours(im1, [box], 0, (0,0,255), 2)

#----Draw one diagonal ----
cv2.line(im1,(box[2][0],box[2][1]),(box[0][0],box[0][1]), (255,0,0),2)

cv2.imwrite("Final_Image.jpg", im1)

This is what I get:

SQUARE:

enter image description here

LOZENGE:

enter image description here

Now since you have obtained the diagonal you have to compare it with a reference line to find the angle in order to determine whether it is a square or not.

For that first draw a reference line (I considered a horizontal line)

cv2.line(im1,(0,10),(im1.shape[1], 10), (255,255,0),2)

You will get :

SQUARE:

enter image description here

LOZENGE:

enter image description here

Now you just have to calculate the angle between these two lines (the diagonal and the reference line):

  1. If the angle is 90 degree or 0 => Lozenge.

  2. Otherwise => Square

How do you calculate angles between two lines?

See THIS POST

Community
  • 1
  • 1
Jeru Luke
  • 20,118
  • 13
  • 80
  • 87
  • thanks @Jeru Luke but how can i get the point of this 2 linescan you give me more information please ? –  Zahra Mar 26 '17 at 12:04
  • I added a photo in my question, did you see it? –  Zahra Mar 26 '17 at 12:12
  • You have added the image now, but I answered the question 18 hours ago!!! You can apply the same technique to your image – Jeru Luke Mar 26 '17 at 17:08
  • yes i edited my question , but how can i get the point of this 2 lines because in this [link](http://stackoverflow.com/questions/13226038/calculating-angle-between-two-lines-in-python) i see that use a point and a vector no ? –  Zahra Mar 26 '17 at 21:14
  • `cv2.line(im1,(box[2][0],box[2][1]),(box[0][0],box[0][1]), (255,0,0),2)` has the points of the diagonal. The point of the reference line is in `cv2.line(im1,(0,10),(im1.shape[1], 10), (255,255,0),2)` – Jeru Luke Mar 27 '17 at 05:59
  • sorry @Jeru Luke, But i dont know how to apply this code so so i added –  Zahra Mar 27 '17 at 10:15