1

I have ued opencv to read the image , convert it to gray scale, and found edges using canny, kernel, thesh, erode and so on and i have detected all the lines in the image using HooughLineP() and i have detected the hours and minutes hand but i also need to find the seconds hand here is the code which i have used

import cv2
import math
import numpy as np
from matplotlib import pyplot as plt
from math import sqrt
from math import acos, degrees


kernel = np.ones((5,5),np.uint8)
img1 = cv2.imread('input1.jpg')
img = cv2.imread('input1.jpg',0)
gray = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)

ret, thresh = cv2.threshold(gray, 50, 255, cv2.THRESH_BINARY)

# Create mask
height,width = img.shape
#height=height-10
#width=width-10
mask = np.zeros((height,width), np.uint8)

edges = cv2.Canny(thresh, 100, 200)

#cv2.imshow('detected ',gray)
cimg=cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1.2, 100)
#circles = cv2.HoughCircles(edges, cv2.HOUGH_GRADIENT, 1.2, 1000, param1 = 50, param2 = 30, minRadius = 20, maxRadius = 0)
for i in circles[0,:]:
    i[2]=i[2]+4
    # Draw on mask
    cv2.circle(mask,(i[0],i[1]),i[2],(255,255,255),thickness=-1)

# Copy that image using that mask
masked_data = cv2.bitwise_and(img1, img1, mask=mask)

# Apply Threshold
_,thresh = cv2.threshold(mask,1,255,cv2.THRESH_BINARY)
# Find Contour
contours = cv2.findContours(thresh,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
x,y,w,h = cv2.boundingRect(contours[0])

# Crop masked_data
crop = masked_data[y+30:y+h-30,x+30:x+w-30]
i=crop
height, width, channels = i.shape
print (width, height, channels)
#########################################################################

ret, mask = cv2.threshold(i, 10, 255, cv2.THRESH_BINARY)
edges = cv2.Canny(i,100,200)
kernel = np.ones((11,11),np.uint8)
kernel2 = np.ones((13,13),np.uint8)
edges = cv2.dilate(edges,kernel,iterations = 1)
edges = cv2.erode(edges,kernel2,iterations = 1)
minLineLength = 1000
maxLineGap = 10
lines = cv2.HoughLinesP(edges,1,np.pi/180,15,minLineLength,maxLineGap)
h=[]
xmax1=0
xmax2=0
ymax1=0
ymax2=0
xs1=0
xs2=0
ys1=0
ys2=0

for line in lines:
    x1, y1, x2, y2 = line[0]
    #cv2.line(i, (x1, y1), (x2, y2), (0, 255, 0), 1)
    dx=x2-x1
    if(dx<0):
        dx=dx*-1
    dy=y2-y1
    if(dy<0):
        dy=dy*-1
        
    hypo=sqrt(dx**2 + dy**2)
    
            
    #print("dx=",dx,"  dy=",dy)
    h.append(hypo)

#print(h)
print(len(h))
a=len(h)
h.sort(reverse=True)
#print(h)
m=0
k=0

for f in range(a):
    for line in lines:
        x1, y1, x2, y2 = line[0]
        #cv2.line(i, (x1, y1), (x2, y2), (0, 255, 0), 3)
        dx=x2-x1
        if(dx<0):
            dx=dx*-1
        dy=y2-y1
        if(dy<0):
            dy=dy*-1

        hypo2=sqrt(dx**2 + dy**2)


        if(hypo2==h[0]):
            m=hypo2
            xmax1=x1
            xmax2=x2
            ymax1=y1
            ymax2=y2
            cv2.line(crop, (xmax1, ymax1), (xmax2, ymax2), (255, 0, 0), 3)
            #print("xmax1=",xmax1," ymax1=",ymax1," xmax2=",xmax2," ymax2=",ymax2)

        if(m==h[0]): 
            if(hypo2==h[f]):
                if((sqrt((xmax2-x2)**2 + (ymax2-y2)**2))>20):
                    if((sqrt((xmax1-x1)**2 + (ymax1-y1)**2))>20):
                        xs1=x1
                        xs2=x2
                        ys1=y1
                        ys2=y2
                        cv2.line(crop, (xs1, ys1), (xs2, ys2), (0, 255, 0), 3)
                        print("xs1=",xs1," ys1=",ys1," xs2=",xs2," ys2=",ys2)
                        k=1
                        break
    if(k==1):                
        break           

print("xmax1=",xmax1," ymax1=",ymax1," xmax2=",xmax2," ymax2=",ymax2)

I have separated the minute's hand and hours hand in the above line of code but i need to separate the seconds hand too, Kindly anyone help me with it!

sample input image

Cris Luengo
  • 55,762
  • 10
  • 62
  • 120
Ajay
  • 55
  • 10

1 Answers1

3

Based on this post: How to detect lines in OpenCV? I have adapted with your image and your crop method, it gives a valid output of the given image :

import cv2
import numpy as np
from matplotlib import pyplot as plt


kernel = np.ones((5,5),np.uint8)
img1 = cv2.imread('clock.jpg')
img = cv2.imread('clock.jpg',0)
gray = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)

ret, thresh = cv2.threshold(gray, 50, 255, cv2.THRESH_BINARY)

# Create mask
height,width = img.shape
mask = np.zeros((height,width), np.uint8)
edges = cv2.Canny(thresh, 100, 200)

#cv2.imshow('detected ',gray)
cimg=cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1.2, 100)
for i in circles[0,:]:
    i[2]=i[2]+4
    # Draw on mask
    cv2.circle(mask,(i[0],i[1]),i[2],(255,255,255),thickness=-1)

# Copy that image using that mask
masked_data = cv2.bitwise_and(img1, img1, mask=mask)

# Apply Threshold
_,thresh = cv2.threshold(mask,1,255,cv2.THRESH_BINARY)
# Find Contour
contours, hierarchy = 
cv2.findContours(thresh,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
x,y,w,h = cv2.boundingRect(contours[0])

# Crop masked_data
crop = masked_data[y+30:y+h-30,x+30:x+w-30]


################################
kernel_size = 5
blur_crop = cv2.GaussianBlur(crop,(kernel_size, kernel_size),0)
low_threshold = 50
high_threshold = 150
edges = cv2.Canny(blur_crop, low_threshold, high_threshold)

rho = 1                     # distance resolution in pixels
theta = np.pi / 180         # angular resolution in radians
threshold = 15              # minimum number of votes 
min_line_length = 100       # minimum number of pixels making up a line
max_line_gap = 10           # maximum gap in pixels between connectable 
line segments
line_image = np.copy(crop) * 0 

# Run Hough on edge detected image
# Output "lines" is an array containing endpoints of detected line
lines = cv2.HoughLinesP(edges, rho, theta, threshold, np.array([]),
                    min_line_length, max_line_gap)

for line in lines:
    for x1,y1,x2,y2 in line:
        cv2.line(line_image,(x1,y1),(x2,y2),(255,0,0),5)

# Draw the lines on the  image
lines_edges = cv2.addWeighted(crop, 0.8, line_image, 1, 0)

cv2.imshow('line_image', line_image)
cv2.imshow('crop', crop)

With some parameter tweaking on the Hough detection you should be able to reduce the results to 3 nice lines. enter image description here

Tiphel
  • 323
  • 1
  • 11
  • Thanks for the reply but I need to separate the seconds hand alone can you help me with it pls – Ajay Jun 25 '21 at 15:21
  • Currently I am working on it can anyone pls join me and help in this project. Here is the colab link where you can find me working pls do help me with it. https://colab.research.google.com/drive/1K377xIBsMpQEnzgOCrnoYu1GMCDTK8V7?usp=sharing – Ajay Jun 25 '21 at 16:02
  • 2
    So you want to find the thinner line. If processing time is not an issue you could apply multiple erosion morphology before the Hough transform. Start with a high erosion value, and iteratively decrease it. Based on the thickness of each hands, you know the first line detected is the hour hand and the third one the seconds hand. – Tiphel Jun 25 '21 at 16:03
  • I am unable to understand it Can you pls solve it and send me I have also share the colab link where I working with that problem – Ajay Jun 25 '21 at 16:05
  • I have updated my code here [For updated code](https://stackoverflow.com/questions/68134235/read-the-analog-clock-image-and-display-the-time-using-the-opencv-python?) , please go through with the code my main problem is I dont know how to separate the seconds hand from other hands, like in my code i have used 2 for loops, in 2nd nested for loop i have separated the x1, x2, y2, y2 coordinated of both minutes and hours but I don't know how to get thus x1, x2, y1, y2 for the seconds hand, Please I am new to this opencv kind of stuff, Please consider it and help me with it @Tiphel – Ajay Jun 26 '21 at 01:37