首页 > 解决方案 > 使用opencv python读取模拟时钟图像并显示时间

问题描述

我尝试使用opencv python读取模拟时钟图像并使用数字图像显示时间,我已经通过使用opencv使用HoughLineP()将时针和分针与图像分开来读取小时和分钟,但我无法将秒针与图像分开,这是我正在使用的代码请帮助我将秒针分开并读取秒值

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

kernel = np.ones((5,5),np.uint8)
img = cv2.imread('input3.jpg')
ret, thresh = cv2.threshold(gray_img, 50, 255, cv2.THRESH_BINARY)

height, width = gray_img.shape
mask = np.zeros((height,width), np.uint8)

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

cimg=cv2.cvtColor(gray_img, cv2.COLOR_GRAY2BGR)

circles = cv2.HoughCircles(gray_img, cv2.HOUGH_GRADIENT, 1.2, 100)


for i in circles[0,:]:
  # print(i) # -> [429.00003 240.6     226.20001]
  i[2] = i[2] + 4
  # used to detect the circle in the image
  cv2.circle(mask, (int(i[0]), int(i[1])), int(i[2]), (255,255,255), thickness=-1)
    
masked_data = cv2.bitwise_and(img, img, mask=mask)

_,thresh = cv2.threshold(mask,1,255,cv2.THRESH_BINARY)

contours,hierarchy = cv2.findContours(thresh,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)

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

height, width, channels = i.shape

ret, mask = cv2.threshold(i, 10, 255, cv2.THRESH_BINARY)

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

kernel = np.ones((11,11),np.uint8)

kernel1 = np.ones((13,13),np.uint8)

edges = cv2.dilate(edges,kernel,iterations = 1)

edges = cv2.erode(edges,kernel1,iterations = 1)

minLineLength = 1000

maxLineGap = 10

lines = cv2.HoughLinesP(edges,
                        1,
                        np.pi/180,
                        15,
                        minLineLength,
                        maxLineGap)


l=[]

# l -> long, s -> short
xl1, xl2, yl1, yl2 = 0, 0, 0 , 0

xs1, xs2, ys1, ys2=0, 0, 0 , 0

for line in lines:

    # getting the values from the line
    x1, y1, x2, y2 = line[0]
    dx = x2 - x1
    if(dx<0):
        dx = dx * -1
    dy = y2 - y1
    if(dy < 0):
        dy = dy * -1
    hypo = sqrt(dx ** 2 + dy ** 2 )

    l.append(hypo)
    

a=len(l) # -> 295

l.sort(reverse=True)
m=0
h=0
    
for f in range(a):

    for line in lines:

        # getting the values from the line
        x1, y1, x2, y2 = line[0]

        
        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 == l[0]):
            m = hypo2
            xl1 = x1
            xl2 = x2
            yl1 = y1
            yl2 = y2

            # getting line region
            cv2.line(crop, (xl1, yl1), (xl2, yl2), (255, 0, 0), 3)
        
        if(m==l[0]):

            if(hypo2 ==l[f]):

                if((sqrt((xl2 - x2)**2 + (yl2 - y2)**2)) > 20):

                    if((sqrt((xl1 - x1)**2 + (yl1 - y1)**2))>20):

                        xs1 = x1
                        xs2 = x2
                        ys1 = y1
                        ys2 = y2

                        # getting line region
                        cv2.line(crop, (xs1, ys1), (xs2, ys2), (0, 255, 0), 3)
                        h=1
                        break

    if(h==1):
        break


xcenter = int(width / 2)
ycenter = int(height / 2)


hour1 = abs(xcenter - xs1)
hour2 = abs(xcenter - xs2)

if(hour1 > hour2):
    xhour = xs1
    yhour = ys1
else:
    xhour = xs2
    yhour = ys2


min1 = abs(xcenter - xl1)
min2 = abs(xcenter - xl2)

if(min1 > min2):
    xmin = xl1
    ymin = yl1
else:
    xmin = xl2
    ymin = yl2

l1 = sqrt( ((xcenter - xhour) ** 2) + ((ycenter - yhour) ** 2) )

l2 = ycenter

l3 = sqrt( ((xcenter - xhour) ** 2) + ((0 - yhour) ** 2) )

cos_theta_hour = ( ( (l1) ** 2 ) + ( (l2) ** 2 ) - ( (l3) ** 2) ) / ( 2 * (l1) * (l2) )
theta_hours_radian = acos(cos_theta_hour)
theta_hours = math.degrees(theta_hours_radian)

if(xhour > xcenter):
    right=1

else:
    right=0


if(right==1):
    hour = int(theta_hours / (6*5))

if(right==0):
    hour = 12 - (int(theta_hours / (6*5)))

if(hour==0):
    hour=12

l1 = sqrt( ((xcenter - xmin) ** 2) + ((ycenter - ymin) ** 2) )

l2 = ycenter

l3 = sqrt( ((xcenter - xmin) ** 2) + ((0 - ymin) ** 2) )

cos_theta_min = ( ( (l1) ** 2 ) + ( (l2) ** 2 ) - ( (l3) ** 2) ) / ( 2 * (l1) * (l2) )
theta_min_radian = acos(cos_theta_min)
theta_min = math.degrees(theta_min_radian)

if(xmin > xcenter):
    right=1

else:
    right=0


if(right==1):
    minute = int(theta_min / ((6*5)/5))

if(right==0):
    minute = 60 - (int(theta_min / ((6*5)/5)))
    if(xmin == xcenter):
        minutes=30

if (minute < 10):
    def display():
        value = "{}:0{}".format(hour,minute)
        digit.config(text = value)
else:
    def display():
        value = "{}:{}".format(hour,minute)
        digit.config(text = value)

canvas = tk.Tk()

canvas.title("Analog to Digital")

canvas.geometry("300x250")

digit = tk.Label(canvas, font=("ds-digital", 65, "bold"), bg="black", fg="blue", bd = 80)

digit.grid(row=0, column = 1)

display()

canvas.mainloop()

这是使用的采样时钟图像

标签: pythonopencvimage-processingclockadc

解决方案


考虑到您检索小时和分钟值的方法是成功的,这里有一个查找秒值的简单解决方案。与时钟图像的二手
相关的某些属性需要在估算其值之前进行一些准备。第一个是颜色。因为手是红色的,所以你有一个很好的引导点将它与图像的其余部分分开。如果您可以使用该功能掩盖图像中二手的红色(在此处阅读更多信息),您将只剩下一个干净的二手图像。之后,您可以使用将其转换为黑白cv2.inRange() cv2.cvtColor()功能。现在,第二个问题可能是二手的细线。您可以使用Morphological Transformations解决这个问题。使用Erosion _ 功能,您可以扩大图像的白色区域并加厚二手。之后,使用您使用的任何方法来查找分针和时针的值,您就可以开始了。


推荐阅读