我已经编译了一个代码,可以使用openCV对汽车进行计数。我尝试使用tkinter将其集成到GUI中,但失败了。我该怎么办?
我尝试在tkinter中创建一个框架,并尝试在该框架中实现汽车跟踪代码,但是失败了。
以下是正常的汽车跟踪代码(除非使用实时网络摄像头作为视频源而导致单个位置索引器超出范围错误,请提供帮助) ):
当前正在使用的视频文件:https://drive.google.com/file/d/1yU5m7SoDQgsqi2UPOzwNE5H_7SyDGKcs/
import numpy as np
import cv2
import pandas as pd
cap = cv2.VideoCapture('traffic.mp4')
# cap = cv2.VideoCapture(0)
frames_count = cap.get(cv2.CAP_PROP_FRAME_COUNT)
fps = cap.get(cv2.CAP_PROP_FPS)
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_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
carscrossedup = 0 # keeps track of cars that crossed up
carscrosseddown = 0 # keeps track of cars that crossed down
carids = [] # blank list to add car ids
caridscrossed = [] # blank list to add car ids that have crossed
totalcars = 0 # keeps track of total cars
fgbg = cv2.createBackgroundSubtractorMOG2() # create background subtractor
ret, frame = cap.read() # import image
ratio = 1 # resize ratio
image = cv2.resize(frame, (0, 0), None, ratio, ratio) # resize image
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 cars
# just have to keep playing around with settings until cars 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), 1)
# line created to stop counting contours, needed as cars in distance become one big contour
lineypos = 225
cv2.line(image, (0, lineypos), (width, lineypos), (255, 0, 0), 2)
# line y position created to count contours
lineypos2 = 250
cv2.line(image, (0, lineypos2), (width, lineypos2), (0, 255, 0), 2)
# 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)
# 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 carids or new carids
if len(cxx): # if there are centroids in the specified area
if not carids: # if carids is empty
for i in range(len(cxx)): # loops through all centroids
carids.append(i) # adds a car id to the empty list carids
df[str(carids[i])] = "" # adds a column to the dataframe corresponding to a carid
# assigns the centroid values to the current frame (row) and carid (column)
df.at[int(framenumber), str(carids[i])] = [cxx[i], cyy[i]]
totalcars = carids[i] + 1 # adds one count to total cars
else: # if there are already car ids
dx = np.zeros((len(cxx), len(carids))) # new arrays to calculate deltas
dy = np.zeros((len(cyy), len(carids))) # new arrays to calculate deltas
for i in range(len(cxx)): # loops through all centroids
for j in range(len(carids)): # loops through all recorded car ids
# acquires centroid from previous frame for specific carid
oldcxcy = df.iloc[int(framenumber - 1)][str(carids[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 car leaves screen and new car shows
continue # continue to next carid
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(carids)): # loops through all current car ids
sumsum = np.abs(dx[:, j]) + np.abs(dy[:, j]) # sums the deltas wrt to car 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 carid
else:
# if delta values are less than maximum radius then add that centroid to that specific carid
if np.abs(mindx) < maxrad and np.abs(mindy) < maxrad:
# adds centroid to corresponding previously existing carid
df.at[int(framenumber), str(carids[j])] = [cxx[minx_index], cyy[miny_index]]
minx_index2.append(minx_index) # appends all the indices that were added to previous carids
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 car needs to be added
if i not in minx_index2 and miny_index2:
df[str(totalcars)] = "" # create another column with total cars
totalcars = totalcars + 1 # adds another total car the count
t = totalcars - 1 # t is a placeholder to total cars
carids.append(t) # append to list of car ids
df.at[int(framenumber), str(t)] = [cxx[i], cyy[i]] # add centroid to the new car 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 car to be added in case minx_index2 is empty
df[str(totalcars)] = "" # create another column with total cars
totalcars = totalcars + 1 # adds another total car the count
t = totalcars - 1 # t is a placeholder to total cars
carids.append(t) # append to list of car ids
df.at[int(framenumber), str(t)] = [cxx[i], cyy[i]] # add centroid to the new car id
# The section below labels the centroids on screen
currentcars = 0 # current cars on screen
currentcarsindex = [] # current cars on screen carid index
for i in range(len(carids)): # loops through all carids
if df.at[int(framenumber), str(carids[i])] != '':
# checks the current frame to see which car ids are active
# by checking in centroid exists on current frame for certain car id
currentcars = currentcars + 1 # adds another to current cars on screen
currentcarsindex.append(i) # adds car ids to current cars on screen
for i in range(currentcars): # loops through all current car ids on screen
# grabs centroid of certain carid for current frame
curcent = df.iloc[int(framenumber)][str(carids[currentcarsindex[i]])]
# grabs centroid of certain carid for previous frame
oldcent = df.iloc[int(framenumber - 1)][str(carids[currentcarsindex[i]])]
if curcent: # if there is a current centroid
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 cars and that car hasn't been counted yet
if oldcent[1] >= lineypos2 and curcent[1] <= lineypos2 and carids[
currentcarsindex[i]] not in caridscrossed:
carscrossedup = carscrossedup + 1
cv2.line(image, (0, lineypos2), (width, lineypos2), (0, 0, 255), 5)
caridscrossed.append(
currentcarsindex[i]) # adds car id to list of count cars to prevent double counting
# checks if old centroid is on or above line and curcent is on or below line
# to count cars and that car hasn't been counted yet
elif oldcent[1] <= lineypos2 and curcent[1] >= lineypos2 and carids[
currentcarsindex[i]] not in caridscrossed:
carscrosseddown = carscrosseddown + 1
cv2.line(image, (0, lineypos2), (width, lineypos2), (0, 0, 125), 5)
caridscrossed.append(currentcarsindex[i])
cv2.putText(image, "Cars out: " + str(carscrossedup), (0, 30), cv2.FONT_HERSHEY_DUPLEX, 0.5, (0, 170, 0), 1)
cv2.putText(image, "Cars in: " + str(carscrosseddown), (0, 45), cv2.FONT_HERSHEY_DUPLEX, 0.5,(0, 170, 0), 1)
# displays images and transformations
cv2.imshow("Car Count", image)
# cv2.moveWindow("countours", 0, 0)
# adds to framecount
framenumber = framenumber + 1
k = cv2.waitKey(int(1000/fps)) & 0xff
if k == 27:
break
else: # if video is finished then break loop
break
cap.release()
cv2.destroyAllWindows()
此外,在将输入源设置为网络摄像头时,出现“单个位置索引器超出范围”错误。有什么解决办法吗?
IndexError Traceback (most recent call last)
<ipython-input-2-6702d1950482> in <module>
220
221 # grabs centroid of certain carid for current frame
--> 222 curcent = df.iloc[int(framenumber)][str(carids[currentcarsindex[i]])]
223
224 # grabs centroid of certain carid for previous frame
c:\users\....\appdata\local\programs\python\python36\lib\site-packages\pandas\core\indexing.py in __getitem__(self, key)
1476
1477 maybe_callable = com._apply_if_callable(key, self.obj)
-> 1478 return self._getitem_axis(maybe_callable, axis=axis)
1479
1480 def _is_scalar_access(self, key):
c:\users\....\appdata\local\programs\python\python36\lib\site-packages\pandas\core\indexing.py in _getitem_axis(self, key, axis)
2100
2101 # validate the location
-> 2102 self._validate_integer(key, axis)
2103
2104 return self._get_loc(key, axis=axis)
c:\users\....\appdata\local\programs\python\python36\lib\site-packages\pandas\core\indexing.py in _validate_integer(self, key, axis)
2007 l = len(ax)
2008 if key >= l or key < -l:
-> 2009 raise IndexError("single positional indexer is out-of-bounds")
2010
2011 def _getitem_tuple(self, tup):
IndexError: single positional indexer is out-of-bounds
以下是我一直在使用的UI代码:
from tkinter import*
import tkinter.messagebox
from tkinter import ttk
import cv2
def main():
root = Tk()
app = PMMain(root)
class WindowPMMain:
def __init__(self, master):
self.master = master
self.master.title("Car Tracking")
#self.master.geometry("1366x715+0+0")
#self.master.state("zoomed")
self.frame = Frame(self.master)
self.frame.pack()
self.LabelTitleMain = Label(self.frame, text = 'Click to start tracking', font = ('arial', 20, 'bold'), bd = 5)
self.LabelTitleMain.grid(row=0, column=0, columnspan =1, pady =10)
###### need help here #####
if __name__ == '__main__':
root = Tk()
b = WindowPMMain(root)
root.mainloop()
我知道输出看起来像下面的图像: https://i.imgur.com/CR6TBej.jpg
当我按下按钮时,跟踪显示在窗口的右半部分,因此我可以将一些其他UI组件与按钮一起放在左侧。
我对这个界面事物是陌生的,很难理解它。实际的方法是使用网络摄像头提要,而不是录制的视频,因为这也存在错误。请帮忙。