1

, поэтому я работаю над проектом робототехники, где мы должны распознать узор на стене и соответствующим образом разместить наш робот. Я разработал этот код обработки изображений на своем ноутбуке, который захватил изображение, преобразовал его в HSV, применил побитую маску, использовал обнаружение края Canny и нашел контуры. Я думал, что могу просто скопировать и вставить код на малину pi 3; однако из-за пониженной вычислительной мощности fps меньше 1. Я пытаюсь выделить код в потоки, поэтому у меня может быть один поток, который захватывает изображения, один поток, который преобразует изображение в HSV и фильтрует его, и один поток для контура. Чтобы они общались друг с другом, я сделал очереди.Обработка изображения на Python

Вот мой исходный код видение:

import numpy as np 
import cv2 
import time 
import matplotlib.pyplot as plt 
import sys 

def onmouse(k, x, y, s, p): 
    global hsv 
    if k == 1: # left mouse, print pixel at x,y 
     print(hsv[y, x]) 

def distance_to_camera(Kwidth, focalLength, pixelWidth): 
    return (Kwidth * focalLength)/pixelWidth 

def contourArea(contours): 

    area = [] 
    for i in range(0,len(contours)): 
     area.append([cv2.contourArea(contours[i]),i]) 

    area.sort() 
    if(area[len(area) - 1] >= 5 * area[0]): 
     return area[len(area)-1] 

    else: return 0 

if __name__ == '__main__': 

    cap = cv2.VideoCapture(0) 

    """ 
    cap.set(3, 1920) 
    cap.set(4, 1080) 
    cap.set(5, 30) 
    time.sleep(2) 
    cap.set(15, -8.0) 
    """ 

    KNOWN_WIDTH = 18 

    # focalLength = focalLength = (rect[1][1] * 74)/18 

    focalLength = 341.7075686984592 

    distance_data = [] 

    counter1 = 0 

    numFrames = 100 
    samples = 1 
    start_time = time.time() 

    while (samples < numFrames): 
     # Capture frame-by-frame 
     ret, img = cap.read() 

     length1, width1, channels = img.shape 
     img = cv2.GaussianBlur(img, (5, 5), 0) 

     hsv = cv2.cvtColor(img.copy(), cv2.COLOR_BGR2HSV) 

     # lower_green = np.array([75, 200, 170]) 
     # lower_green = np.array([53,180,122]) 

     #lower_green = np.array([70, 120, 120]) 

     lower_green = np.array([70, 50, 120]) 

     upper_green = np.array([120, 200, 255]) 

     #upper_green = np.array([120, 200, 255]) 

     mask = cv2.inRange(hsv, lower_green, upper_green) 
     res = cv2.bitwise_and(hsv, hsv, mask=mask) 

     gray = cv2.cvtColor(res, cv2.COLOR_BGR2GRAY) 

     edged = cv2.Canny(res, 35, 125) 

     im2, contours, hierarchy = cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE) 

     if (len(contours) > 1): 

      area,place = contourArea(contours) 

      #print(area) 
      if(area != 0): 

       # print("Contxours: %d" % contours.size()) 
       # print("Hierarchy: %d" % hierarchy.size()) 

       c = contours[place] 

       cv2.drawContours(img, c, -1, (0, 0, 255), 3) 
       cv2.drawContours(edged,c, -1, (255, 0, 0), 3) 
       perimeter = cv2.arcLength(c, True) 

       M = cv2.moments(c) 

       cx = 0 
       cy = 0 

       if (M['m00'] != 0): 
        cx = int(M['m10']/M['m00']) # Center of MASS Coordinates 
        cy = int(M['m01']/M['m00']) 

       rect = cv2.minAreaRect(c) 
       box = cv2.boxPoints(rect) 
       box = np.int0(box) 
       cv2.drawContours(img, [box], 0, (255, 0, 0), 2) 
       cv2.circle(img, (cx, cy), 7, (0, 0, 255), -1) 

       cv2.line(img, (int(width1/2), int(length1/2)), (cx, cy), (255, 0, 0), 2) 


       if(rect[1][1] != 0): 
        inches = distance_to_camera(KNOWN_WIDTH, focalLength, rect[1][1]) 

        #print(inches) 
        distance_data.append(inches) 

       counter1+=1 
     samples+=1 
     """ 
     cv2.namedWindow("Image w Contours") 
     cv2.setMouseCallback("Image w Contours", onmouse) 
     cv2.imshow('Image w Contours', img) 

     cv2.namedWindow("HSV") 
     cv2.setMouseCallback("HSV", onmouse) 
     cv2.imshow('HSV', edged) 

     if cv2.waitKey(1) & 0xFF == ord('x'): 
      break 
     """ 

# When everything done, release the capture 

    totTime = time.time() - start_time 
    print("--- %s seconds ---" % (totTime)) 
    print('----%s fps ----' % (numFrames/totTime)) 
    cap.release() 
    cv2.destroyAllWindows() 

    --- 13.469419717788696 seconds --- 
    ----7.42422480665093 fps ---- 


    plt.plot(distance_data) 
    plt.xlabel('TimeData') 
    plt.ylabel('Distance to Target(in) ') 
    plt.title('Distance vs Time From Camera') 
    plt.show() 

Это мой шитый код, который захватывает кадры в основном и фильтрует ее в другом потоке; Я хотел бы иметь еще один поток для контурного фитинга, но даже с этими двумя процессами код с резьбой имеет почти тот же FPS, что и предыдущий код. Также эти результаты получены от моего ноутбука, а не от малины.

import cv2 
import threading 
import datetime 
import numpy as np 
import queue 
import time 

frame = queue.Queue(0) 
canny = queue.Queue(0) 
lower_green = np.array([70, 50, 120]) 
upper_green = np.array([120, 200, 255]) 

class FilterFrames(threading.Thread): 
    def __init__(self,threadID,lock): 
     threading.Thread.__init__(self) 
     self.lock = lock 
     self.name = threadID 
     self.setDaemon(True) 
     self.start() 

    def run(self): 

     while(True): 
      img1 = frame.get() 
      img1 = cv2.GaussianBlur(img1, (5, 5), 0) 
      hsv = cv2.cvtColor(img1.copy(), cv2.COLOR_BGR2HSV) 
      mask = cv2.inRange(hsv, lower_green, upper_green) 
      res = cv2.bitwise_and(hsv, hsv, mask=mask) 
      edged = cv2.Canny(res, 35, 125) 
      canny.put(edged) 

if __name__ == '__main__': 

    lock = threading.Lock() 
    numframes = 100 
    frames = 0 

    cap = cv2.VideoCapture(0) 

    filter = FilterFrames(lock=lock, threadID='Filter') 

    start_time = time.time() 
    while(frames < numframes): 

     ret,img = cap.read() 

     frame.put(img) 

     frames+=1 

    totTime = time.time() - start_time 
    print("--- %s seconds ---" % (totTime)) 
    print('----%s fps ----' % (numframes/totTime)) 

    """ 
    Results were: 

    --- 13.590131759643555 seconds --- 
    ----7.358280388197121 fps ---- 

    """ 
    cap.release() 

мне было интересно, если есть что-то я делаю не так, является ли доступ к очереди замедляется код, и если я должен использовать модуль многопроцессорной вместо резьбы для этого приложения.

ответ

1

Вы можете прокомментировать код, используя cProfile модуль. Он расскажет вам, какая часть программы является узким местом.

Python в реализации CPython имеет глобальную блокировку интерпретатора (GIL). Это означает, что даже если ваше приложение многопоточно, оно будет использовать только один из ваших процессоров. Вы можете попробовать multiprocessing модуль. Хотя Jython и IronPython не имеют GIL, у них нет ни одной, ни стабильной поддержки Python3.

В вашем коде self.lock не используется. Используйте хорошую IDE с pylint, чтобы поймать подобные ошибки. Очереди сохраняют свои собственные блокировки.

threading.Thread.__init__(self) - устаревший синтаксис, исходящий от Python2. Вместо этого использовать super().__init__()