Python Opencv视频帧的ROI提取

Python Opencv视频帧的ROI提取,python,pandas,opencv,roi,Python,Pandas,Opencv,Roi,如何从OpenCV视频帧中提取ROI 我已经开发了一个跟踪和计数系统的代码。我需要帮助在代码中实现更多的逻辑 需要帮助部分:提取对象穿过参考线时的图像。 我想提取具有矩形框ROI的对象的图像 下面是我的代码: import numpy as np import cv2 import pandas as pd cap = cv2.VideoCapture('traffic.mp4') frames_count, fps, width, height = cap.get(cv2.CAP_PROP_

如何从OpenCV视频帧中提取ROI

我已经开发了一个跟踪和计数系统的代码。我需要帮助在代码中实现更多的逻辑

需要帮助部分:提取对象穿过参考线时的图像。
我想提取具有矩形框ROI的对象的图像

下面是我的代码:

import numpy as np
import cv2
import pandas as pd

cap = cv2.VideoCapture('traffic.mp4')
frames_count, fps, width, height = cap.get(cv2.CAP_PROP_FRAME_COUNT), cap.get(cv2.CAP_PROP_FPS), cap.get(
    cv2.CAP_PROP_FRAME_WIDTH), cap.get(cv2.CAP_PROP_FRAME_HEIGHT)
width = int(width)
height = int(height)

# creates a pandas data frame with the number of rows the same length as frame count
df = pd.DataFrame(index=range(int(frames_count)))
df.index.name = "Frames"

framenumber = 0  # keeps track of current frame
Chocolatecrossedup = 0  # keeps track of Chocolates that crossed up
Chocolatecrosseddown = 0  # keeps track of Chocolates that crossed down
Chocolateids = []  # blank list to add Chocolate ids
Chocolateidscrossed = []  # blank list to add Chocolate ids that have crossed
totalChocolates = 0  # keeps track of total Chocolates

fgbg = cv2.createBackgroundSubtractorMOG2()  # create background subtractor

# information to start saving a video file
ret, frame = cap.read()  # import image
ratio = .5  # resize ratio
image = cv2.resize(frame, (0, 0), None, ratio, ratio)  # resize image
width2, height2, channels = image.shape
video = cv2.VideoWriter('Chocolate_counter.avi', cv2.VideoWriter_fourcc('M', 'J', 'P', 'G'), fps, (height2, width2), 1)

while True:

    ret, frame = cap.read()  # import image

    if ret:  # if there is a frame continue with code

        image = cv2.resize(frame, (0, 0), None, ratio, ratio)  # resize image

        gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)  # converts image to gray

        fgmask = fgbg.apply(gray)  # uses the background subtraction

        # applies different thresholds to fgmask to try and isolate Chocolates
        # just have to keep playing around with settings until Chocolates are easily identifiable
        kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))  # kernel to apply to the morphology
        closing = cv2.morphologyEx(fgmask, cv2.MORPH_CLOSE, kernel)
        opening = cv2.morphologyEx(closing, cv2.MORPH_OPEN, kernel)
        dilation = cv2.dilate(opening, kernel)
        retvalbin, bins = cv2.threshold(dilation, 220, 255, cv2.THRESH_BINARY)  # removes the shadows

        # creates contours
        contours, hierarchy = cv2.findContours(bins, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

        # use convex hull to create polygon around contours
        hull = [cv2.convexHull(c) for c in contours]

        # draw contours
        #cv2.drawContours(image, hull, -1, (0, 255, 0), 3)

        # line created to stop counting contours, needed as Chocolates in distance become one big contour
        lineypos = 225
        cv2.line(image, (0, lineypos), (width, lineypos), (255, 0, 0), 5)

        # line y position created to count contours
        lineypos2 = 250
        cv2.line(image, (0, lineypos2), (width, lineypos2), (0, 255, 0), 5)

        # min area for contours in case a bunch of small noise contours are created
        minarea = 300

        # max area for contours, can be quite large for buses
        maxarea = 50000

        # vectors for the x and y locations of contour centroids in current frame
        cxx = np.zeros(len(contours))
        cyy = np.zeros(len(contours))

        for i in range(len(contours)):  # cycles through all contours in current frame

            if hierarchy[0, i, 3] == -1:  # using hierarchy to only count parent contours (contours not within others)

                area = cv2.contourArea(contours[i])  # area of contour

                if minarea < area < maxarea:  # area threshold for contour

                    # calculating centroids of contours
                    cnt = contours[i]
                    M = cv2.moments(cnt)
                    cx = int(M['m10'] / M['m00'])
                    cy = int(M['m01'] / M['m00'])

                    if cy > lineypos:  # filters out contours that are above line (y starts at top)

                        # gets bounding points of contour to create rectangle
                        # x,y is top left corner and w,h is width and height
                        x, y, w, h = cv2.boundingRect(cnt)

                        # creates a rectangle around contour
                        cv2.rectangle(image, (x, y), (x + w, y + h), (255, 0, 0), 2)

                        # Prints centroid text in order to double check later on
                        cv2.putText(image, str(cx) + "," + str(cy), (cx + 10, cy + 10), cv2.FONT_HERSHEY_SIMPLEX,
                                    .3, (0, 0, 255), 1)

                        cv2.drawMarker(image, (cx, cy), (0, 0, 255), cv2.MARKER_STAR, markerSize=5, thickness=1,
                                       line_type=cv2.LINE_AA)

                        # adds centroids that passed previous criteria to centroid list
                        cxx[i] = cx
                        cyy[i] = cy

        # eliminates zero entries (centroids that were not added)
        cxx = cxx[cxx != 0]
        cyy = cyy[cyy != 0]

        # empty list to later check which centroid indices were added to dataframe
        minx_index2 = []
        miny_index2 = []

        # maximum allowable radius for current frame centroid to be considered the same centroid from previous frame
        maxrad = 25

        # The section below keeps track of the centroids and assigns them to old Chocolateids or new Chocolateids

        if len(cxx):  # if there are centroids in the specified area

            if not Chocolateids:  # if Chocolateids is empty

                for i in range(len(cxx)):  # loops through all centroids

                    Chocolateids.append(i)  # adds a Chocolate id to the empty list Chocolateids
                    df[str(Chocolateids[i])] = ""  # adds a column to the dataframe corresponding to a Chocolateid

                    # assigns the centroid values to the current frame (row) and Chocolateid (column)
                    df.at[int(framenumber), str(Chocolateids[i])] = [cxx[i], cyy[i]]

                    totalChocolates = Chocolateids[i] + 1  # adds one count to total Chocolates

            else:  # if there are already Chocolate ids

                dx = np.zeros((len(cxx), len(Chocolateids)))  # new arrays to calculate deltas
                dy = np.zeros((len(cyy), len(Chocolateids)))  # new arrays to calculate deltas

                for i in range(len(cxx)):  # loops through all centroids

                    for j in range(len(Chocolateids)):  # loops through all recorded Chocolate ids

                        # acquires centroid from previous frame for specific Chocolateid
                        oldcxcy = df.iloc[int(framenumber - 1)][str(Chocolateids[j])]

                        # acquires current frame centroid that doesn't necessarily line up with previous frame centroid
                        curcxcy = np.array([cxx[i], cyy[i]])

                        if not oldcxcy:  # checks if old centroid is empty in case Chocolate leaves screen and new Chocolate shows

                            continue  # continue to next Chocolateid

                        else:  # calculate centroid deltas to compare to current frame position later

                            dx[i, j] = oldcxcy[0] - curcxcy[0]
                            dy[i, j] = oldcxcy[1] - curcxcy[1]

                for j in range(len(Chocolateids)):  # loops through all current Chocolate ids

                    sumsum = np.abs(dx[:, j]) + np.abs(dy[:, j])  # sums the deltas wrt to Chocolate ids

                    # finds which index carid had the min difference and this is true index
                    correctindextrue = np.argmin(np.abs(sumsum))
                    minx_index = correctindextrue
                    miny_index = correctindextrue

                    # acquires delta values of the minimum deltas in order to check if it is within radius later on
                    mindx = dx[minx_index, j]
                    mindy = dy[miny_index, j]

                    if mindx == 0 and mindy == 0 and np.all(dx[:, j] == 0) and np.all(dy[:, j] == 0):
                        # checks if minimum value is 0 and checks if all deltas are zero since this is empty set
                        # delta could be zero if centroid didn't move

                        continue  # continue to next Chocolateid

                    else:

                        # if delta values are less than maximum radius then add that centroid to that specific Chocolateid
                        if np.abs(mindx) < maxrad and np.abs(mindy) < maxrad:

                            # adds centroid to corresponding previously existing Chocolateid
                            df.at[int(framenumber), str(Chocolateids[j])] = [cxx[minx_index], cyy[miny_index]]
                            minx_index2.append(minx_index)  # appends all the indices that were added to previous Chocolateids
                            miny_index2.append(miny_index)

                for i in range(len(cxx)):  # loops through all centroids

                    # if centroid is not in the minindex list then another Chocolate needs to be added
                    if i not in minx_index2 and miny_index2:

                        df[str(totalChocolates)] = ""  # create another column with total Chocolates
                        totalChocolates = totalChocolates + 1  # adds another total Chocolate the count
                        t = totalChocolates - 1  # t is a placeholder to total Chocolates
                        Chocolateids.append(t)  # append to list of Chocolate ids
                        df.at[int(framenumber), str(t)] = [cxx[i], cyy[i]]  # add centroid to the new Chocolate id

                    elif curcxcy[0] and not oldcxcy and not minx_index2 and not miny_index2:
                        # checks if current centroid exists but previous centroid does not
                        # new Chocolate to be added in case minx_index2 is empty

                        df[str(totalChocolates)] = ""  # create another column with total Chocolates
                        totalChocolates = totalChocolates + 1  # adds another total Chocolate the count
                        t = totalChocolates - 1  # t is a placeholder to total Chocolates
                        Chocolateids.append(t)  # append to list of Chocolate ids
                        df.at[int(framenumber), str(t)] = [cxx[i], cyy[i]]  # add centroid to the new Chocolate id

        # The section below labels the centroids on screen

        currentChocolates = 0  # current Chocolates on screen
        currentChocolatesindex = []  # current Chocolates on screen Chocolateid index

        for i in range(len(Chocolateids)):  # loops through all Chocolateids

            if df.at[int(framenumber), str(Chocolateids[i])] != '':
                # checks the current frame to see which Chocolate ids are active
                # by checking in centroid exists on current frame for certain Chocolate id

                currentChocolates = currentChocolates + 1  # adds another to current Chocolates on screen
                currentChocolatesindex.append(i)  # adds Chocolate ids to current Chocolates on screen

        for i in range(currentChocolates):  # loops through all current Chocolate ids on screen

            # grabs centroid of certain Chocolateid for current frame
            curcent = df.iloc[int(framenumber)][str(Chocolateids[currentChocolatesindex[i]])]

            # grabs centroid of certain Chocolateid for previous frame
            oldcent = df.iloc[int(framenumber - 1)][str(Chocolateids[currentChocolatesindex[i]])]

            if curcent:  # if there is a current centroid

                # On-screen text for current centroid
                cv2.putText(image, "Centroid" + str(curcent[0]) + "," + str(curcent[1]),
                            (int(curcent[0]), int(curcent[1])), cv2.FONT_HERSHEY_SIMPLEX, .5, (0, 255, 255), 2)

                cv2.putText(image, "ID:" + str(Chocolateids[currentChocolatesindex[i]]), (int(curcent[0]), int(curcent[1] - 15)),
                            cv2.FONT_HERSHEY_SIMPLEX, .5, (0, 255, 255), 2)

                cv2.drawMarker(image, (int(curcent[0]), int(curcent[1])), (0, 0, 255), cv2.MARKER_STAR, markerSize=5,
                               thickness=1, line_type=cv2.LINE_AA)

                if oldcent:  # checks if old centroid exists
                    # adds radius box from previous centroid to current centroid for visualization
                    xstart = oldcent[0] - maxrad
                    ystart = oldcent[1] - maxrad
                    xwidth = oldcent[0] + maxrad
                    yheight = oldcent[1] + maxrad
                    cv2.rectangle(image, (int(xstart), int(ystart)), (int(xwidth), int(yheight)), (0, 125, 0), 1)

                    # checks if old centroid is on or below line and curcent is on or above line
                    # to count Chocolates and that Chocolate hasn't been counted yet
                    if oldcent[1] >= lineypos2 and curcent[1] <= lineypos2 and Chocolateids[
                        currentChocolatesindex[i]] not in Chocolateidscrossed:

                        Chocolatecrossedup = Chocolatecrossedup + 1
                        cv2.line(image, (0, lineypos2), (width, lineypos2), (0, 0, 255), 5)
                        Chocolateidscrossed.append(
                            currentChocolatesindex[i])  # adds Chocolate id to list of count Chocolate to prevent double counting

                    # checks if old centroid is on or above line and curcent is on or below line
                    # to count Chocolates and that Chocolate hasn't been counted yet
                    elif oldcent[1] <= lineypos2 and curcent[1] >= lineypos2 and Chocolateids[
                        currentChocolatesindex[i]] not in Chocolateidscrossed:

                        Chocolatecrosseddown = Chocolatecrosseddown + 1
                        cv2.line(image, (0, lineypos2), (width, lineypos2), (0, 0, 125), 5)
                        Chocolateidscrossed.append(currentChocolatesindex[i])

        # Top left hand corner on-screen text
        cv2.rectangle(image, (0, 0), (250, 100), (255, 0, 0), -1)  # background rectangle for on-screen text

        cv2.putText(image, "Chocolates in Area: " + str(currentChocolates), (0, 15), cv2.FONT_HERSHEY_SIMPLEX, .5, (0, 170, 0), 1)

        cv2.putText(image, "Chocolates Crossed Down: " + str(Chocolatecrosseddown), (0, 45), cv2.FONT_HERSHEY_SIMPLEX, .5,(0, 170, 0), 1)

        cv2.putText(image, "Total Chocolates Detected: " + str(len(Chocolateids)), (0, 60), cv2.FONT_HERSHEY_SIMPLEX, .5, (0, 170, 0), 1)

        cv2.putText(image, 'Time: ' + str(round(framenumber / fps, 2)) + ' sec of ' + str(round(frames_count / fps, 2)) + ' sec', (0, 90), cv2.FONT_HERSHEY_SIMPLEX, .5, (0, 170, 0), 1)

        # displays images and transformations
        cv2.imshow("countours", image)
        cv2.moveWindow("countours", 0, 0)

        video.write(image)  # save the current image to video file from earlier

        # adds to framecount
        framenumber = framenumber + 1

        k = cv2.waitKey(int(1000/fps)) & 0xff  # int(1000/fps) is normal speed since waitkey is in ms
        if k == 27:
            break

    else:  
        break

cap.release()
cv2.destroyAllWindows()

将numpy导入为np
进口cv2
作为pd进口熊猫
cap=cv2.VideoCapture('traffic.mp4')
帧数,fps,宽度,高度=cap.get(cv2.cap\u PROP\u FRAME\u count),cap.get(cv2.cap\u PROP\u fps),cap.get(
cv2.CAP\u PROP\u FRAME\u WIDTH),CAP.get(cv2.CAP\u PROP\u FRAME\u HEIGHT)
宽度=int(宽度)
高度=整数(高度)
#创建行数与帧计数长度相同的数据帧
df=pd.DataFrame(index=range(int(frames\u count)))
df.index.name=“帧”
framenumber=0#跟踪当前帧
Chocolatecrossedup=0#跟踪交叉的巧克力
ChocolatedCrossedDown=0#跟踪向下交叉的巧克力
ChocolateID=[]#添加巧克力ID的空白列表
ChocolatedIdscrossed=[]#空白列表以添加已交叉的巧克力ID
totalChocolates=0#记录巧克力总量
fgbg=cv2.createBackgroundSubtractorMOG2()#创建背景减法器
#开始保存视频文件的信息
ret,frame=cap.read()#导入图像
比率=.5#调整大小比率
image=cv2.调整大小(帧,(0,0),无,比率,比率)#调整图像大小
宽度2,高度2,通道=image.shape
video=cv2.VideoWriter('Chocolate_counter.avi',cv2.VideoWriter_fourcc('M','J','P','G'),fps,(高2,宽2),1)
尽管如此:
ret,frame=cap.read()#导入图像
if ret:#如果有帧,则继续代码
image=cv2.调整大小(帧,(0,0),无,比率,比率)#调整图像大小
gray=cv2.CVT颜色(图像,cv2.COLOR_BGR2GRAY)#将图像转换为灰色
fgmask=fgbg.apply(灰色)#使用背景减法
#对fgmask应用不同的阈值以尝试隔离巧克力
#只要不断地摆弄摆设,直到巧克力很容易辨认出来
kernel=cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5))#应用于形态学的内核
closing=cv2.morphologyEx(fgmask,cv2.MORPH\u CLOSE,kernel)
opening=cv2.morphologyEx(closing,cv2.MORPH_OPEN,kernel)
扩张=cv2。扩张(打开,内核)
retvalbin,bins=cv2.threshold(膨胀,220255,cv2.THRESH_BINARY)#移除阴影
#创建轮廓
等高线,层次=cv2.findContours(箱子,cv2.RETR\u树,cv2.CHAIN\u近似值\u简单)
#使用凸面外壳线围绕轮廓创建多边形
外壳=[cv2.convexHull(c)表示轮廓中的c]
#画轮廓
#cv2.绘制轮廓(图像,船体,-1,(0,255,0),3)
#当远处的巧克力变成一个大轮廓时,为了停止计算轮廓而创建的线
lineypos=225
线(图像,(0,lineypos),(宽度,lineypos),(255,0,0),5)
#为计算轮廓而创建的y线位置
lineypos2=250
cv2.线条(图像,(0,lineypos2),(宽度,lineypos2),(0,255,0),5)
#创建一组小噪声轮廓时轮廓的最小面积
米纳雷=300
#等高线的最大面积,对于公交车来说可能相当大
最大面积=50000
#当前帧中轮廓质心的x和y位置的向量
cxx=np.零(透镜(轮廓))
cyy=np.零(透镜(轮廓))
对于范围内的i(len(等高线)):#循环当前帧中的所有等高线
如果层次结构[0,i,3]=-1:#使用层次结构仅计算父轮廓(不在其他轮廓内)
面积=cv2.轮廓面积(轮廓[i])#轮廓面积
如果minarealineypos:#过滤掉线上方的轮廓(y从顶部开始)
#获取轮廓的边界点以创建矩形
#x,y是左上角,w,h是宽度和高度
x、 y,w,h=cv2.boundingRect(cnt)
#围绕轮廓创建一个矩形
矩形(图像,(x,y),(x+w,y+h),(255,0,0),2)
#打印质心文本,以便稍后再次检查
cv2.putText(图像,str(cx)+“,”+str(cy),(cx+10,cy+10),cv2.FONT\u HERSHEY\u SIMPLEX,
.3, (0, 0, 255), 1)
cv2.drawMarker(图像,(cx,cy),(0,0,255),cv2.MARKER_星形,markerSize=5,厚度=1,
线路类型=cv2.线路类型(AA)
#将通过先前条件的质心添加到质心列表中
cxx[i]=cx
cyy[i]=cy
#消除零项(未添加的质心)
cxx=cxx[cxx!=0]
cyy=cyy[cyy!=0]
#空列表,以稍后检查哪些质心索引已添加到数据帧
minx_index2=[]
miny_index2=[]
#当前帧质心的最大允许半径与前一帧的质心相同
maxrad=25
#下面的部分跟踪质心,并将其分配给旧巧克力或新巧克力
if len(cxx):#指定区域是否有质心
如果不是巧克力糖:#如果巧克力糖是空的
对于范围内的i(len(cxx)):#通过所有质心循环
巧克力