欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

OpenCV 表盤指針自動讀數(shù)的示例代碼

 更新時(shí)間:2020年04月10日 10:40:06   作者:胖虎賣湯圓  
這篇文章主要介紹了OpenCV 表盤指針自動讀數(shù)的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

前段時(shí)間參加了一個(gè)表盤指針讀數(shù)的比賽,今天來總結(jié)一下

數(shù)據(jù)集一共有一千張圖片:

方法一:徑向灰度求和

基本原理:

將圖像以表盤圓心轉(zhuǎn)換成極坐標(biāo),然后通過矩陣按行求和找到二值圖最大值即為指針尖端

導(dǎo)入需要用到的包

import cv2 as cv
import numpy as np
import math
from matplotlib import pyplot as plt
import os

圖像預(yù)處理

去除背景:利用提取紅色實(shí)現(xiàn)

def extract_red(image):
  """
  通過紅色過濾提取出指針
  """
  red_lower1 = np.array([0, 43, 46])
  red_upper1 = np.array([10, 255, 255])
  red_lower2 = np.array([156, 43, 46])
  red_upper2 = np.array([180, 255, 255])
  dst = cv.cvtColor(image, cv.COLOR_BGR2HSV)
  mask1 = cv.inRange(dst, lowerb=red_lower1, upperb=red_upper1)
  mask2 = cv.inRange(dst, lowerb=red_lower2, upperb=red_upper2)
  mask = cv.add(mask1, mask2)
  return mask

獲得鐘表中心:輪廓查找,取出輪廓的外接矩形,根據(jù)矩形面積找出圓心

def get_center(image):
  """
  獲取鐘表中心
  """ 
  edg_output = cv.Canny(image, 100, 150, 2) # canny算子提取邊緣
  cv.imshow('dsd', edg_output)
  # 獲取圖片輪廓
  contours, hireachy = cv.findContours(edg_output, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
  center = []
  cut=[0, 0]
  for i, contour in enumerate(contours):
    x, y, w, h = cv.boundingRect(contour) # 外接矩形
    area = w * h # 面積
    if area < 100 or area > 4000:
      continue
    cv.rectangle(image, (x, y), (x + w, y + h), (255, 0, 0), 1)
    cx = w / 2
    cy = h / 2
    cv.circle(image, (np.int(x + cx), np.int(y + cy)), 1, (255, 0, 0)) ## 在圖上標(biāo)出圓心
    center = [np.int(x + cx), np.int(y + cy)]
    break
  return center[::-1]

由上面的圖像可以看出,圓心定位還是非常準(zhǔn)確的

圖片裁剪

def ChangeImage(image):
  """
  圖像裁剪
  """
  # 指針提取
  mask = extract_red(image)
  mask = cv.medianBlur(mask,ksize=5)#去噪
  # 獲取中心
  center = get_center(mask)
  # 去除多余黑色邊框
  [y, x] = center
  cut = mask[y-300:y+300, x-300:x+300]
  # 因?yàn)閙ask處理后已經(jīng)是二值圖像,故不用轉(zhuǎn)化為灰度圖像
  return cut

剪裁后的圖像如下圖所示:

極坐標(biāo)轉(zhuǎn)換

注意:需要將圖片裁剪成正方形

def polar(image):
  """
  轉(zhuǎn)換成極坐標(biāo)
  """
  x, y = 300, 300
  maxRadius = 300*math.sqrt(2)
  linear_polar = cv.linearPolar(image, (y, x), maxRadius, cv.WARP_FILL_OUTLIERS + cv.INTER_LINEAR)
  mypolar = linear_polar.copy()
  #將圖片調(diào)整為從0度開始
  mypolar[:150, :] = linear_polar[450:, :]
  mypolar[150:, :] = linear_polar[:450, :]
  cv.imshow("linear_polar", linear_polar)
  cv.imshow("mypolar", mypolar)
  return mypolar


由圖像就可以很容易發(fā)現(xiàn)指針的頂點(diǎn)

計(jì)算角度

def Get_Reading(sumdata):
  """
  讀數(shù)并輸出
  """
  peak = []
  # s記錄遍歷時(shí)波是否在上升
  s = sumdata[0] < sumdata[1]
  for i in range(599):
    # 上升階段
    if s==True and sumdata[i] > sumdata[i+1] and sumdata[i] > 70000:
      peak.append(sumdata[i])
      s=False
    # 下降階段
    if s==False and sumdata[i] < sumdata[i+1]:
      s=True
  peak.sort()
  a = sumdata[0]
  b = sumdata[-1]
  if not peak or max(a,b) > peak[-1]:
    peak.append(max(a,b))
  longindex = (sumdata.index(peak[-1]))%599
  longnum = (longindex + 1)//25*50
  # 先初始化和長的同一刻度
  #shortindex = longindex
  shortnum = round(longindex / 6)
  try:
    shortindex = sumdata.index(peak[-2])
    shortnum = round(shortindex / 6)
  except IndexError:
    i=0
    while i<300:
      i += 1
      l = sumdata[(longindex-i)%600]
      r = sumdata[(longindex+i)%600]
      possibleshort = max(l,r)
      # 在短指針可能范圍內(nèi)尋找插值符合條件的值
      if possibleshort > 80000:
        continue
      elif possibleshort < 60000:
        break
      else:
        if abs(l-r) > 17800:
          shortindex = sumdata.index(possibleshort) - 1
          shortnum = round(shortindex / 6)
          break
  return [longnum,shortnum%100]
def test():
  """
  RGS法測試
  """
  image = cv.imread("./BONC/1_{0:0>4d}".format(400) + ".jpg")
  newimg = ChangeImage(image)
  polarimg = polar(newimg)
  psum = polarimg.sum(axis=1, dtype = 'int32')
  result = Get_Reading(list(psum))
  print(result)
if __name__ == "__main__":
  test()
  k = cv.waitKey(0)
  if k == 27:
    cv.destroyAllWindows()
  elif k == ord('s'):
    cv.imwrite('new.jpg', src)
    cv.destroyAllWindows()

[1050, 44]

方法二:Hough直線檢測

原理:利用Hough變換檢測出指針的兩條邊,從而兩條邊的中線角度即為指針刻度

數(shù)據(jù)預(yù)處理與上面的方法類似

可以看到分別檢測出了兩個(gè)指針的左右兩條邊,然后可以由這四個(gè)角度算出兩個(gè)指針中線的角度,具體計(jì)算過程寫的有點(diǎn)復(fù)雜

class Apparatus:
  def __init__(self, name):
    self.name = name
    self.angle = []
    self.src = cv.imread(name)


  def line_detect_possible_demo(self, image, center, tg):
    '''
    :param image: 二值圖
    :param center: 圓心
    :param tg: 直線檢測maxLineGap
    '''
    res = {} # 存放線段的斜率和信息
    edges = cv.Canny(image, 50, 150, apertureSize=7)
    cv.imshow("abcdefg", edges)
    lines = cv.HoughLinesP(edges, 1, np.pi/360, 13, minLineLength=20, maxLineGap=tg)
    for line in lines:
      x_1, y_1, x_2, y_2 = line[0]
      # 將坐標(biāo)原點(diǎn)移動到圓心
      x1 = x_1 - center[0]
      y1 = center[1] - y_1
      x2 = x_2 - center[0]
      y2 = center[1] - y_2

      # 計(jì)算斜率
      if x2 - x1 == 0:
        k = float('inf')
      else:
        k = (y2-y1)/(x2-x1)
      d1 = np.sqrt(max(abs(x2), abs(x1)) ** 2 + (max(abs(y2), abs(y1))) ** 2) # 線段長度
      d2 = np.sqrt(min(abs(x2), abs(x1)) ** 2 + (min(abs(y2), abs(y1))) ** 2)
      # 將長指針與短指針做標(biāo)記
      if d1 < 155 and d1 > 148 and d2 > 115:
        res[k] = [1]
      elif d1 < 110 and d1 > 100 and d2 > 75:
        res[k] = [2]
      else:
        continue
      res[k].append(1) if (x2 + x1) /2 > 0 else res[k].append(0) # 將14象限與23象限分離
      cv.line(self.src, (x1 + center[0], center[1] - y1), (x2 + center[0], center[1] - y2), (255, 0, 0), 1)
      cv.imshow("line_detect-posssible_demo", self.src)


      # 計(jì)算線段中點(diǎn)的梯度來判斷是指針的左側(cè)線段還是右側(cè)線段
      middle_x = int((x_1 + x_2) / 2)
      middle_y = int((y_1 + y_2) / 2)
      grad_mat = image[middle_y-5:middle_y+6, middle_x-5:middle_x+6]
      cv.imshow("grad_mat", grad_mat)
      grad_x = cv.Sobel(grad_mat, cv.CV_32F, 1, 0)
      grad_y = cv.Sobel(grad_mat, cv.CV_32F, 0, 1)
      gradx = np.max(grad_x) if np.max(grad_x) != 0 else np.min(grad_x)
      grady = np.max(grad_y) if np.max(grad_y) != 0 else np.min(grad_y)
      if ((gradx >=0 and grady >= 0) or (gradx <= 0 and grady >= 0)) and res[k][1] == 1:
        res[k].append(1) # 右測
      elif ((gradx <= 0 and grady <= 0) or (gradx >= 0 and grady <= 0)) and res[k][1] == 0:
        res[k].append(1)
      else:
        res[k].append(0) # 左側(cè)
    # 計(jì)算角度
    angle1 = [i for i in res if res[i][0] == 1]
    angle2 = [i for i in res if res[i][0] == 2]
    # 長指針
    a = np.arctan(angle1[0])
    b = np.arctan(angle1[1])
    if a * b < 0 and max(abs(a), abs(b)) > np.pi / 4:
      if a + b < 0:
        self.angle.append(math.degrees(-(a + b) / 2)) if res[angle1[1]][1] == 1 else self.angle.append(
          math.degrees(-(a + b) / 2) + 180)
      else:
        self.angle.append(math.degrees(np.pi - (a + b) / 2)) if res[angle1[1]][1] == 1 else self.angle.append(
          math.degrees(np.pi - (a + b) / 2) + 180)
    else:
      self.angle.append(math.degrees(np.pi / 2 - (a + b) / 2)) if res[angle1[1]][1] == 1 else self.angle.append(math.degrees(np.pi / 2 - (a + b) / 2) + 180)
    print('長指針讀數(shù):%f' % self.angle[0])


    # 短指針
    a = np.arctan(angle2[0])
    b = np.arctan(angle2[1])
    if a * b < 0 and max(abs(a), abs(b)) > np.pi / 4:
      if a + b < 0:
        self.angle.append(math.degrees(-(a + b) / 2)) if res[angle2[1]][1] == 1 else self.angle.append(
          math.degrees(-(a + b) / 2) + 180)
      else:
        self.angle.append(math.degrees(np.pi - (a + b) / 2)) if res[angle2[1]][1] == 1 else self.angle.append(
          math.degrees(np.pi - (a + b) / 2) + 180)
    else:
      self.angle.append(math.degrees(np.pi / 2 - (a + b) / 2)) if res[angle2[1]][1] == 1 else self.angle.append(math.degrees(np.pi / 2 - (a + b) / 2) + 180)
    print('短指針讀數(shù):%f' % self.angle[1])



  def get_center(self, mask):
    edg_output = cv.Canny(mask, 66, 150, 2)
    cv.imshow('edg', edg_output)
    # 外接矩形
    contours, hireachy = cv.findContours(edg_output, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
    center = []
    for i, contour in enumerate(contours):
      x, y, w, h = cv.boundingRect(contour) # 外接矩形
      area = w * h # 面積
      if area > 1000 or area < 40:
        continue
      #print(area)
      # cv.circle(src, (np.int(cx), np.int(cy)), 3, (255), -1)
      cv.rectangle(self.src, (x, y), (x + w, y + h), (255, 0, 0), 1)
      cx = w / 2
      cy = h / 2
      cv.circle(self.src, (np.int(x + cx), np.int(y + cy)), 1, (255, 0, 0))
      center.extend([np.int(x + cx), np.int(y + cy)])
      break

    cv.imshow('center', self.src)
    return center


  def extract(self, image):
    red_lower1 = np.array([0, 43, 46])
    red_lower2 = np.array([156, 43, 46])
    red_upper1 = np.array([10, 255, 255])
    red_upper2 = np.array([180, 255, 255])
    frame = cv.cvtColor(image, cv.COLOR_BGR2HSV)
    mask1 = cv.inRange(frame, lowerb=red_lower1, upperb=red_upper1)
    mask2 = cv.inRange(frame, lowerb=red_lower2, upperb=red_upper2)
    mask = cv.add(mask1, mask2)
    mask = cv.bitwise_not(mask)
    cv.imshow('mask', mask)
    return mask


  def test(self):
    self.src = cv.resize(self.src, dsize=None, fx=0.5, fy=0.5) # 此處可以修改插值方式interpolation
    mask = self.extract(self.src)
    mask = cv.medianBlur(mask, ksize=5) # 去噪
    # 獲取中心
    center = self.get_center(mask)
    # 去除多余黑色邊框
    [y, x] = center
    mask = mask[x - 155:x + 155, y - 155:y + 155]
    cv.imshow('mask', mask)
    #self.find_short(center, mask)
    try:
      self.line_detect_possible_demo(mask, center, 20)
    except IndexError:
      try:
        self.src = cv.imread(self.name)
        self.src = cv.resize(self.src, dsize=None, fx=0.5, fy=0.5) # 此處可以修改插值方式interpolation
        self.src = cv.convertScaleAbs(self.src, alpha=1.4, beta=0)
        blur = cv.pyrMeanShiftFiltering(self.src, 10, 17)
        mask = self.extract(blur)
        self.line_detect_possible_demo(mask, center, 20)
      except IndexError:
        self.src = cv.imread(self.name)
        self.src = cv.resize(self.src, dsize=None, fx=0.5, fy=0.5) # 此處可以修改插值方式interpolation
        self.src = cv.normalize(self.src, dst=None, alpha=200, beta=10, norm_type=cv.NORM_MINMAX)
    
        blur = cv.pyrMeanShiftFiltering(self.src, 10, 17)
        mask = self.extract(blur)
        self.line_detect_possible_demo(mask, center, 20)


if __name__ == '__main__':
  apparatus = Apparatus('./BONC/1_0555.jpg')
  # 讀取圖片
  apparatus.test()
  k = cv.waitKey(0)
  if k == 27:
    cv.destroyAllWindows()
  elif k == ord('s'):
    cv.imwrite('new.jpg', apparatus.src)
    cv.destroyAllWindows()

長指針讀數(shù):77.070291
短指針讀數(shù):218.896747

由結(jié)果可以看出精確度還是挺高的,但是這種方法有三個(gè)缺點(diǎn):

  • 當(dāng)兩個(gè)指針重合時(shí)候不太好處理
  • 有時(shí)候hough直線檢測只能檢測出箭頭的一條邊,這時(shí)候就會報(bào)錯(cuò),可以利用圖像增強(qiáng)、角點(diǎn)檢測和圖像梯度來輔助解決,但是效果都不太好
  • 計(jì)算角度很復(fù)雜?。。ㄒ部赡苁俏蚁霃?fù)雜了,不過這段代碼確實(shí)花了大量時(shí)間)

代碼里可能還有很多問題,希望大家多多指出

到此這篇關(guān)于OpenCV 表盤指針自動讀數(shù)的示例代碼的文章就介紹到這了,更多相關(guān)OpenCV 表盤自動讀數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • python實(shí)現(xiàn)維吉尼亞算法

    python實(shí)現(xiàn)維吉尼亞算法

    這篇文章主要為大家詳細(xì)介紹了python編程實(shí)現(xiàn)維吉尼亞算法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-03-03
  • python+opencv圖像分割實(shí)現(xiàn)分割不規(guī)則ROI區(qū)域方法匯總

    python+opencv圖像分割實(shí)現(xiàn)分割不規(guī)則ROI區(qū)域方法匯總

    這篇文章主要介紹了python+opencv圖像分割實(shí)現(xiàn)分割不規(guī)則ROI區(qū)域方法匯總,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • python基礎(chǔ)_文件操作實(shí)現(xiàn)全文或單行替換的方法

    python基礎(chǔ)_文件操作實(shí)現(xiàn)全文或單行替換的方法

    下面小編就為大家?guī)硪黄猵ython基礎(chǔ)_文件操作實(shí)現(xiàn)全文或單行替換的方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-09-09
  • python中csv文件數(shù)據(jù)顏色設(shè)置方式

    python中csv文件數(shù)據(jù)顏色設(shè)置方式

    這篇文章主要介紹了python中csv文件數(shù)據(jù)顏色設(shè)置方式,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-02-02
  • Python的加密模塊之hashlib 與 base64詳解及常用加密方法

    Python的加密模塊之hashlib 與 base64詳解及常用加密方法

    我們來學(xué)習(xí)一下 Python 中的加密模塊,加密模塊在工作中被廣泛應(yīng)用,比如數(shù)據(jù)的傳入 不希望被捕獲,通過把數(shù)據(jù)加密。這樣即使被捕獲也無法獲取到數(shù)據(jù)的真實(shí)信息,今天我們就來學(xué)習(xí)一下關(guān)于加密的方法,感興趣的朋友跟隨小編一起看看吧
    2023-02-02
  • python加密打包程序詳解

    python加密打包程序詳解

    這篇文章主要介紹了python加密打包程序,還給大家介紹了Python實(shí)現(xiàn)文件簡單加解密的方法,本文通過示例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2023-04-04
  • Python3+cgroupspy安裝使用簡介

    Python3+cgroupspy安裝使用簡介

    cgroups是Control groups的簡稱,是Linux內(nèi)核提供的一種限制進(jìn)程使用和種系統(tǒng)資源的特性,這篇文章主要介紹了Python3+cgroupspy安裝使用教程,需要的朋友可以參考下
    2023-04-04
  • Python 如何在字符串中插入變量

    Python 如何在字符串中插入變量

    這篇文章主要介紹了Python 如何在字符串中插入變量,文中講解非常細(xì)致,代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-08-08
  • python實(shí)現(xiàn)幾種歸一化方法(Normalization Method)

    python實(shí)現(xiàn)幾種歸一化方法(Normalization Method)

    這篇文章主要介紹了python實(shí)現(xiàn)幾種歸一化方法(Normalization Method),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-07-07
  • 在SQLite-Python中實(shí)現(xiàn)返回、查詢中文字段的方法

    在SQLite-Python中實(shí)現(xiàn)返回、查詢中文字段的方法

    今天小編就為大家分享一篇在SQLite-Python中實(shí)現(xiàn)返回、查詢中文字段的方法,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-07-07

最新評論