最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

 更新時(shí)間:2020年04月10日 10:40:06   作者:胖虎賣湯圓  
這篇文章主要介紹了OpenCV 表盤指針自動(dòng)讀數(shù)的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(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
  # 先初始化和長(zhǎng)的同一刻度
  #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法測(cè)試
  """
  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直線檢測(cè)

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

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

可以看到分別檢測(cè)出了兩個(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: 直線檢測(cè)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)移動(dòng)到圓心
      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) # 線段長(zhǎng)度
      d2 = np.sqrt(min(abs(x2), abs(x1)) ** 2 + (min(abs(y2), abs(y1))) ** 2)
      # 將長(zhǎng)指針與短指針做標(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) # 右測(cè)
      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]
    # 長(zhǎng)指針
    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('長(zhǎng)指針讀數(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()

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

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

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

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

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

相關(guān)文章

  • linux系統(tǒng)使用python獲取cpu信息腳本分享

    linux系統(tǒng)使用python獲取cpu信息腳本分享

    這篇文章主要介紹了linux系統(tǒng)使用python獲取cpu信息腳本,大家參考使用吧
    2014-01-01
  • 如何用itertools解決無序排列組合的問題

    如何用itertools解決無序排列組合的問題

    下面小編就為大家?guī)硪黄绾斡胕tertools解決無序排列組合的問題。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-05-05
  • pandas讀取csv文件,分隔符參數(shù)sep的實(shí)例

    pandas讀取csv文件,分隔符參數(shù)sep的實(shí)例

    今天小編就為大家分享一篇pandas讀取csv文件,分隔符參數(shù)sep的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2018-12-12
  • Python 將 CSV 分割成多個(gè)文件的示例代碼

    Python 將 CSV 分割成多個(gè)文件的示例代碼

    在本文中,我們討論了如何使用 Pandas 庫創(chuàng)建 CSV 文件, 此外,我們還討論了兩種常見的數(shù)據(jù)拆分技術(shù),行式數(shù)據(jù)拆分和列式數(shù)據(jù)拆分,需要的朋友可以參考下
    2023-06-06
  • python?使用enumerate()函數(shù)詳解

    python?使用enumerate()函數(shù)詳解

    enumerate()是python的內(nèi)置函數(shù),將一個(gè)可遍歷iterable數(shù)據(jù)對(duì)象,組合為一個(gè)索引序列,同時(shí)列出數(shù)據(jù)和數(shù)據(jù)下標(biāo),一般用在for循環(huán)當(dāng)中,這篇文章主要介紹了python?使用enumerate()函數(shù),需要的朋友可以參考下
    2022-11-11
  • python實(shí)現(xiàn)發(fā)送QQ郵件(可加附件)

    python實(shí)現(xiàn)發(fā)送QQ郵件(可加附件)

    這篇文章主要為大家詳細(xì)介紹了python實(shí)現(xiàn)發(fā)送QQ郵件,可添加附件功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-12-12
  • opencv繪制矩形和圓的實(shí)現(xiàn)

    opencv繪制矩形和圓的實(shí)現(xiàn)

    本文主要介紹了opencv繪制矩形和圓的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-02-02
  • Python中json.dumps()函數(shù)的使用解析

    Python中json.dumps()函數(shù)的使用解析

    json.dumps將一個(gè)Python數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)換為JSON,本文介紹了Python中json.dumps()函數(shù)的具體使用方法,以及和dump的區(qū)別,感興趣的可以了解一下
    2021-05-05
  • python使用BeautifulSoup與正則表達(dá)式爬取時(shí)光網(wǎng)不同地區(qū)top100電影并對(duì)比

    python使用BeautifulSoup與正則表達(dá)式爬取時(shí)光網(wǎng)不同地區(qū)top100電影并對(duì)比

    這篇文章主要給大家介紹了關(guān)于python使用BeautifulSoup與正則表達(dá)式爬取時(shí)光網(wǎng)不同地區(qū)top100電影并對(duì)比的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用python具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • 利用Python實(shí)現(xiàn)圖書超期提醒

    利用Python實(shí)現(xiàn)圖書超期提醒

    很多人喜歡逛圖書館,時(shí)不時(shí)去借本書,但每本書可能只可以借兩個(gè)月,一旦超期不還就會(huì)進(jìn)行相應(yīng)的處罰!為什么不寫個(gè)腳本來通知自己圖書超期呢?說了這么多廢話,我們就進(jìn)入主題吧!??!
    2016-08-08

最新評(píng)論

同仁县| 大埔区| 景宁| 尖扎县| 宁波市| 宁津县| 屏边| 高雄市| 上栗县| 咸丰县| 郯城县| 太仆寺旗| 阳泉市| 泰州市| 泾源县| 措美县| 广昌县| 吉木乃县| 东丰县| 聂拉木县| 湖口县| 伊吾县| 赣州市| 民和| 仁化县| 巴林左旗| 泾源县| 漳平市| 台中县| 哈尔滨市| 清镇市| 玛纳斯县| 怀远县| 赤水市| 正宁县| 方正县| 松溪县| 广丰县| 象州县| 攀枝花市| 鹿泉市|