diff --git a/simba/ROI_draw_defined.py b/simba/ROI_draw_defined.py index 63c8c8ab5..22b5daac0 100644 --- a/simba/ROI_draw_defined.py +++ b/simba/ROI_draw_defined.py @@ -1,279 +1,279 @@ -from configparser import ConfigParser -import os -import cv2 -import numpy as np -import pandas as pd -import warnings -import glob - -def roiByDefinition(inifile): - global ix, iy - global topLeftStatus - global overlay - global topLeftX, topLeftY, bottomRightX, bottomRightY - global ix, iy - global centerStatus - global overlay - global currCircleRadius - global centerX, centerY, radius - global centroids, toRemoveShapeName, removeStatus, toRemoveShape - global recWidth, recHeight, firstLoop - config = ConfigParser() - configFile = str(inifile) - warnings.filterwarnings('ignore',category=pd.io.pytables.PerformanceWarning) - pd.options.mode.chained_assignment = None - config.read(configFile) - vidInfPath = config.get('General settings', 'project_path') - videofilesFolder = os.path.join(vidInfPath, "videos") - logFolderPath = os.path.join(vidInfPath, 'logs') - vidInfPath = os.path.join(logFolderPath, 'video_info.csv') - vidinfDf = pd.read_csv(vidInfPath) - rectangularDf = pd.DataFrame(columns=['Video', "Shape_type", "Name", "width", "height", "topLeftX", "topLeftY"]) - circleDf = pd.DataFrame(columns=['Video', "Shape_type", "Name", "centerX", "centerY", "radius"]) - fscale = 0.02 - space_scale = 1.1 - outPutPath = os.path.join(logFolderPath, 'measures') - ROIcoordinatesPath = os.path.join(outPutPath, 'ROI_definitions.h5') - rectanglesInfo = pd.read_hdf(ROIcoordinatesPath, key='rectangles') - circleInfo = pd.read_hdf(ROIcoordinatesPath, key='circleDf') - - # mouse callback function - def draw_rectangle(event,x,y,flags,param): - global ix,iy - global topLeftStatus - global overlay - global topLeftX, topLeftY, bottomRightX, bottomRightY - if (event == cv2.EVENT_LBUTTONDBLCLK): - print(topLeftStatus) - topLeftX, topLeftY, bottomRightX, bottomRightY = (x, y, x+currRecWidth, y+currRecHeight) - print(topLeftX, topLeftY, bottomRightX, bottomRightY) - if topLeftStatus == True: - overlay = img.copy() - cv2.rectangle(overlay, (topLeftX, topLeftY), (bottomRightX, bottomRightY), (255, 0, 0), 3) - cv2.imshow('Define shape', overlay) - topLeftStatus = True - - def draw_circle(event,x,y,flags,param): - global ix,iy - global centerStatus - global overlay - global currCircleRadius - global centerX, centerY, radius - global overlay - if (event == cv2.EVENT_LBUTTONDBLCLK): - centerX, centerY, radius = (int(x), int(y), int(currCircleRadius)) - if centerStatus == True: - overlay = img.copy() - cv2.circle(overlay, (centerX, centerY), radius, (144, 0, 255), 2) - cv2.imshow('Define shape', overlay) - centerStatus = True - - - def select_shape_to_change(event, x, y, flags, param): - global centroids, toRemoveShapeName, removeStatus, toRemoveShape - if (event == cv2.EVENT_LBUTTONDBLCLK): - toRemove = centroids[(centroids['CenterX'] <= x+20) & (centroids['CenterX'] >= x-20) & (centroids['CenterY'] <= y+20) & (centroids['CenterY'] >= y-20)] - toRemoveShapeName, toRemoveShape = (toRemove["Name"].iloc[0], toRemove["Shape"].iloc[0]) - updateImage(centroids, toRemoveShapeName) - removeStatus = False - - def select_new_shape_centroid_loc(event, x, y, flags, param): - global toRemoveShapeName, removeStatus - if (event == cv2.EVENT_LBUTTONDBLCLK): - toInsertShapeName, toInsertShape = toRemoveShapeName, toRemoveShape - toRemoveShapeName = '' - if toInsertShape == 'rectangle': - newTopLeftX, newTopLeftY = (int(x -(recWidth/2)), int((y -(recHeight/2)))) - currRectangleDf.loc[(currRectangleDf['Name'] == toInsertShapeName), 'topLeftX'] = newTopLeftX - currRectangleDf.loc[(currRectangleDf['Name'] == toInsertShapeName), 'topLeftY'] = newTopLeftY - if toInsertShape == 'circle': - newcenterX, newcenterY = (int(x), int(y)) - currCirclesDf.loc[(currCirclesDf['Name'] == toInsertShapeName), 'centerX'] = newcenterX - currCirclesDf.loc[(currCirclesDf['Name'] == toInsertShapeName), 'centerY'] = newcenterY - removeStatus = True - updateImage(centroids, toRemoveShapeName) - - videofilesFound = glob.glob(videofilesFolder + '/*.mp4') - cap = cv2.VideoCapture(videofilesFound[0]) - cap.set(1, 0) - ret, frame = cap.read() - fileName = str(0) + str('.bmp') - filePath = os.path.join(videofilesFolder, fileName) - cv2.imwrite(filePath,frame) - img = cv2.imread(filePath) - CurrVidName = os.path.basename(videofilesFound[0]).replace('.mp4', '') - CurrVidSet = vidinfDf.loc[vidinfDf['Video'] == CurrVidName] - try: - videoHeight = int(CurrVidSet['Resolution_height']) - videoWidth = int(CurrVidSet['Resolution_width']) - currPixPerMM = float(CurrVidSet['pixels/mm']) - except TypeError: - print('Error: make sure all the videos that are going to be analyzed are represented in the project_folder/logs/video_info.csv file') - fontScale = min(videoWidth, videoHeight) / (25 / fscale) - spacingScale = int(min(videoWidth, videoHeight) / (25 / space_scale)) - - ##### RECTANGLES #### - currRectangleDf = rectanglesInfo.loc[rectanglesInfo['Video'] == str(CurrVidName)] - shapeType = 'rectangle' - addSpacer = 2 - for index, row in currRectangleDf.iterrows(): - currRecName, currRecWidth,currRecHeight = (row['Name'], int(row['width']*currPixPerMM), int(row['height']*currPixPerMM)) - im = np.zeros((videoHeight, videoWidth, 3)) - cv2.putText(im, str(CurrVidName), (10, (videoHeight - videoHeight) + spacingScale), cv2.FONT_HERSHEY_SIMPLEX, fontScale,(0, 255, 0), 2) - cv2.putText(im, 'Draw rectangle: ' + str(currRecName), (10, (videoHeight - videoHeight) + spacingScale * addSpacer), cv2.FONT_HERSHEY_SIMPLEX, fontScale, (0, 255, 0), 2) - addSpacer+=1 - cv2.putText(im, 'Pre-specified size: ' + str(row['width']) + 'x' + str(row['height']) + 'mm', (10, (videoHeight - videoHeight) + spacingScale * addSpacer), cv2.FONT_HERSHEY_SIMPLEX, fontScale, (0, 255, 0), 2) - addSpacer+=1 - cv2.putText(im, 'Instructions', (10, (videoHeight - videoHeight) + spacingScale * addSpacer), cv2.FONT_HERSHEY_SIMPLEX, fontScale, (255, 255, 255), 2) - addSpacer+=1 - cv2.putText(im, str('Double left click at the top right corner of the rectangle'), (10, (videoHeight - videoHeight )+ spacingScale * addSpacer), cv2.FONT_HERSHEY_SIMPLEX, fontScale, (255, 255, 255), 2) - addSpacer+=1 - cv2.putText(im, str('Press ESC to start or to continue'), (10, (videoHeight - videoHeight) + spacingScale * addSpacer), cv2.FONT_HERSHEY_SIMPLEX, fontScale, (255, 255, 255), 2) - while (1): - cv2.imshow('Instructions', im) - k = cv2.waitKey(0) - addSpacer = 2 - if k==27: # Esc key to stop - break - - cv2.namedWindow('Define shape', cv2.WINDOW_NORMAL) - ix, iy = -1, -1 - overlay = img.copy() - topLeftStatus = False - while (1): - cv2.setMouseCallback('Define shape', draw_rectangle) - cv2.imshow('Define shape', overlay) - k = cv2.waitKey(20) - if k == 27: - boxList = [CurrVidName, shapeType, currRecName, currRecWidth, currRecHeight, topLeftX, topLeftY] - rectangularDf = rectangularDf.append(pd.Series(dict(zip(rectangularDf.columns, boxList))), ignore_index=True) - img = overlay.copy() - cv2.destroyWindow('Define shape') - break - - ##### CIRCLES #### - currCirclesDf = circleInfo.loc[circleInfo['Video'] == str(CurrVidName)] - shapeType = 'circle' - for index, row in currCirclesDf.iterrows(): - currCircleName, currCircleRadius = (row['Name'], row['Radius']*currPixPerMM) - im = np.zeros((videoHeight, videoWidth, 3)) - addSpacer += 1 - cv2.putText(im, str(CurrVidName), (10, (videoHeight - videoHeight) + spacingScale), cv2.FONT_HERSHEY_SIMPLEX, fontScale + 0.15,(144, 0, 255), 2) - addSpacer += 1 - cv2.putText(im, 'Draw circle: ' + str(currCircleName), (10, (videoHeight - videoHeight) + spacingScale * addSpacer), cv2.FONT_HERSHEY_SIMPLEX, fontScale + 0.2, (144, 0, 255), 2) - addSpacer += 1 - cv2.putText(im, 'Instructions', (10, (videoHeight - videoHeight) + spacingScale * addSpacer), cv2.FONT_HERSHEY_SIMPLEX, fontScale, (255, 255, 255), 2) - addSpacer += 1 - cv2.putText(im, str('Double left click to specify the center of the circle'), (10, (videoHeight - videoHeight) + spacingScale * addSpacer), cv2.FONT_HERSHEY_SIMPLEX, fontScale + 0.025, (255, 255, 255), 2) - addSpacer += 1 - cv2.putText(im, str('Press ESC or Enter to start or to continue'), (10, (videoHeight - videoHeight) + spacingScale * addSpacer), cv2.FONT_HERSHEY_SIMPLEX, fontScale + 0.05, (255, 255, 255), 2) - while (1): - cv2.imshow('Instructions', im) - k = cv2.waitKey(33) - if k==27: # Esc key to stop - break - overlay = img.copy() - ix, iy = -1, -1 - cv2.namedWindow('Define shape', cv2.WINDOW_NORMAL) - centerStatus = False - while (1): - cv2.setMouseCallback('Define shape',draw_circle) - cv2.imshow('Define shape', overlay) - k = cv2.waitKey(20) & 0xFF - if k == 27: - circList = [CurrVidName, shapeType, currCircleName, centerX, centerY, radius] - circleDf = circleDf.append(pd.Series(dict(zip(circleDf.columns, circList))),ignore_index=True) - img = overlay.copy() - cv2.destroyWindow('Define shape') - break - - duplicatedRec, duplicatedCirc = (rectangularDf.copy(), circleDf.copy()) - - for othervids in videofilesFound[1:]: - currVidName = os.path.basename(othervids).replace('.mp4', '') - duplicatedRec['Video'], duplicatedCirc['Video'] = (currVidName, currVidName) - rectangularDf = rectangularDf.append(duplicatedRec, ignore_index=True) - circleDf = circleDf.append(duplicatedCirc, ignore_index=True) - - def updateImage(centroids, toRemoveShapeName): - global recWidth, recHeight, firstLoop - overlay = img.copy() - centroids = centroids.drop_duplicates() - for rectangle in range(len(currRectangleDf)): - videoName, recName, topLeftX, topLeftY = (currRectangleDf['Video'].iloc[rectangle], currRectangleDf['Name'].iloc[rectangle], currRectangleDf['topLeftX'].iloc[rectangle],currRectangleDf['topLeftY'].iloc[rectangle]) - if recName == toRemoveShapeName: - recWidth, recHeight = (currRectangleDf['width'].iloc[rectangle], currRectangleDf['height'].iloc[rectangle]) - continue - else: - bottomRightX, bottomRightY = (topLeftX + currRectangleDf['width'].iloc[rectangle], topLeftY + currRectangleDf['height'].iloc[rectangle]) - cv2.rectangle(overlay, (topLeftX, topLeftY), (bottomRightX, bottomRightY), (255, 0, 0), 10) - centerOfShape = [(topLeftX + bottomRightX) / 2, (topLeftY + bottomRightY) / 2] - cv2.circle(overlay, (int(centerOfShape[0]), int(centerOfShape[1])), 12, (255, 0, 0), -1) - if firstLoop == True: - CentroidList = [CurrVidName, 'rectangle', recName, centerOfShape[0], centerOfShape[1]] - centroids = centroids.append(pd.Series(dict(zip(centroids.columns, CentroidList))), ignore_index=True) - else: - centroids.loc[(centroids['Name'] == recName), 'CenterX'] = centerOfShape[0] - centroids.loc[(centroids['Name'] == recName), 'CenterY'] = centerOfShape[1] - correctionMask = (rectangularDf['Name'] == recName) & (rectangularDf['Video'] == videoName) - rectangularDf['topLeftX'][correctionMask], rectangularDf['topLeftY'][correctionMask] = topLeftX, topLeftY - for circle in range(len(currCirclesDf)): - videoName, circleName, centerX, centerY, radius = (currCirclesDf['Video'].iloc[circle], currCirclesDf['Name'].iloc[circle], currCirclesDf['centerX'].iloc[circle], currCirclesDf['centerY'].iloc[circle], currCirclesDf['radius'].iloc[circle]) - if circleName == toRemoveShapeName: - continue - else: - cv2.circle(overlay, (centerX, centerY), radius, (144, 0, 255), 2) - cv2.circle(overlay, (centerX, centerY), 12, (144, 0, 255), -1) - if firstLoop == True: - CentroidList = [CurrVidName, 'circle', circleName, centerX, centerY] - centroids = centroids.append(pd.Series(dict(zip(centroids.columns, CentroidList))), ignore_index=True) - else: - centroids.loc[(centroids['Name'] == circleName), 'CenterX'] = centerX - centroids.loc[(centroids['Name'] == circleName), 'CenterY'] = centerY - correctionMask = (circleDf['Name'] == circleName) & (circleDf['Video'] == videoName) - circleDf['centerX'][correctionMask], circleDf['centerY'][correctionMask] = centerX, centerY - firstLoop = False - cv2.imshow('Define shape', overlay) - return centroids - cv2.namedWindow('Define shape', cv2.WINDOW_NORMAL) - for videos in videofilesFound[1:]: - firstLoop = True - cap = cv2.VideoCapture(videos) - cap.set(1, 0) - ret, frame = cap.read() - fileName = str(0) + str('.bmp') - filePath = os.path.join(videofilesFolder, fileName) - cv2.imwrite(filePath, frame) - img = cv2.imread(filePath) - overlay = img.copy() - CurrVidName = os.path.basename(videos).replace('.mp4', '') - currRectangleDf = rectangularDf.loc[rectanglesInfo['Video'] == str(CurrVidName)] - currCirclesDf = circleDf.loc[circleInfo['Video'] == str(CurrVidName)] - centroids = pd.DataFrame(columns=['Video', "Shape", "Name", "CenterX", "CenterY"]) - toRemoveShapeName = '' - removeStatus = True - ix, iy = -1, -1 - while (1): - centroids = updateImage(centroids, toRemoveShapeName) - if removeStatus == True: - cv2.setMouseCallback('Define shape', select_shape_to_change) - if removeStatus == False: - cv2.setMouseCallback('Define shape', select_new_shape_centroid_loc) - k = cv2.waitKey(50) & 0xFF - if k == 27: - cv2.destroyWindow('Define shape') - cv2.destroyWindow('Instructions') - break - break - - storePath = os.path.join(outPutPath, 'ROI_definitions.h5') - store = pd.HDFStore(storePath) - store['rectangles'] = rectangularDf - store['circleDf'] = circleDf - polygonDf = pd.DataFrame(columns=['Video', "Shape_type", "Name", "vertices"]) - store['polygons'] = polygonDf - print('ROI definitions saved in ' + str('storePath')) - store.close() - print(rectangularDf) - print(circleDf) +from configparser import ConfigParser +import os +import cv2 +import numpy as np +import pandas as pd +import warnings +import glob + +def roiByDefinition(inifile): + global ix, iy + global topLeftStatus + global overlay + global topLeftX, topLeftY, bottomRightX, bottomRightY + global ix, iy + global centerStatus + global overlay + global currCircleRadius + global centerX, centerY, radius + global centroids, toRemoveShapeName, removeStatus, toRemoveShape + global recWidth, recHeight, firstLoop + config = ConfigParser() + configFile = str(inifile) + warnings.filterwarnings('ignore',category=pd.io.pytables.PerformanceWarning) + pd.options.mode.chained_assignment = None + config.read(configFile) + vidInfPath = config.get('General settings', 'project_path') + videofilesFolder = os.path.join(vidInfPath, "videos") + logFolderPath = os.path.join(vidInfPath, 'logs') + vidInfPath = os.path.join(logFolderPath, 'video_info.csv') + vidinfDf = pd.read_csv(vidInfPath) + rectangularDf = pd.DataFrame(columns=['Video', "Shape_type", "Name", "width", "height", "topLeftX", "topLeftY"]) + circleDf = pd.DataFrame(columns=['Video', "Shape_type", "Name", "centerX", "centerY", "radius"]) + fscale = 0.02 + space_scale = 1.1 + outPutPath = os.path.join(logFolderPath, 'measures') + ROIcoordinatesPath = os.path.join(outPutPath, 'ROI_definitions.h5') + rectanglesInfo = pd.read_hdf(ROIcoordinatesPath, key='rectangles') + circleInfo = pd.read_hdf(ROIcoordinatesPath, key='circleDf') + + # mouse callback function + def draw_rectangle(event,x,y,flags,param): + global ix,iy + global topLeftStatus + global overlay + global topLeftX, topLeftY, bottomRightX, bottomRightY + if (event == cv2.EVENT_LBUTTONDBLCLK): + print(topLeftStatus) + topLeftX, topLeftY, bottomRightX, bottomRightY = (x, y, x+currRecWidth, y+currRecHeight) + print(topLeftX, topLeftY, bottomRightX, bottomRightY) + if topLeftStatus == True: + overlay = img.copy() + cv2.rectangle(overlay, (topLeftX, topLeftY), (bottomRightX, bottomRightY), (255, 0, 0), 3) + cv2.imshow('Define shape', overlay) + topLeftStatus = True + + def draw_circle(event,x,y,flags,param): + global ix,iy + global centerStatus + global overlay + global currCircleRadius + global centerX, centerY, radius + global overlay + if (event == cv2.EVENT_LBUTTONDBLCLK): + centerX, centerY, radius = (int(x), int(y), int(currCircleRadius)) + if centerStatus == True: + overlay = img.copy() + cv2.circle(overlay, (centerX, centerY), radius, (144, 0, 255), 2) + cv2.imshow('Define shape', overlay) + centerStatus = True + + + def select_shape_to_change(event, x, y, flags, param): + global centroids, toRemoveShapeName, removeStatus, toRemoveShape + if (event == cv2.EVENT_LBUTTONDBLCLK): + toRemove = centroids[(centroids['CenterX'] <= x+20) & (centroids['CenterX'] >= x-20) & (centroids['CenterY'] <= y+20) & (centroids['CenterY'] >= y-20)] + toRemoveShapeName, toRemoveShape = (toRemove["Name"].iloc[0], toRemove["Shape"].iloc[0]) + updateImage(centroids, toRemoveShapeName) + removeStatus = False + + def select_new_shape_centroid_loc(event, x, y, flags, param): + global toRemoveShapeName, removeStatus + if (event == cv2.EVENT_LBUTTONDBLCLK): + toInsertShapeName, toInsertShape = toRemoveShapeName, toRemoveShape + toRemoveShapeName = '' + if toInsertShape == 'rectangle': + newTopLeftX, newTopLeftY = (int(x -(recWidth/2)), int((y -(recHeight/2)))) + currRectangleDf.loc[(currRectangleDf['Name'] == toInsertShapeName), 'topLeftX'] = newTopLeftX + currRectangleDf.loc[(currRectangleDf['Name'] == toInsertShapeName), 'topLeftY'] = newTopLeftY + if toInsertShape == 'circle': + newcenterX, newcenterY = (int(x), int(y)) + currCirclesDf.loc[(currCirclesDf['Name'] == toInsertShapeName), 'centerX'] = newcenterX + currCirclesDf.loc[(currCirclesDf['Name'] == toInsertShapeName), 'centerY'] = newcenterY + removeStatus = True + updateImage(centroids, toRemoveShapeName) + + videofilesFound = glob.glob(videofilesFolder + '/*.mp4') + glob.glob(videofilesFolder + '/*.avi') + cap = cv2.VideoCapture(videofilesFound[0]) + cap.set(1, 0) + ret, frame = cap.read() + fileName = str(0) + str('.bmp') + filePath = os.path.join(videofilesFolder, fileName) + cv2.imwrite(filePath,frame) + img = cv2.imread(filePath) + CurrVidName = os.path.splitext(os.path.basename(videofilesFound[0]))[0] + CurrVidSet = vidinfDf.loc[vidinfDf['Video'] == CurrVidName] + try: + videoHeight = int(CurrVidSet['Resolution_height']) + videoWidth = int(CurrVidSet['Resolution_width']) + currPixPerMM = float(CurrVidSet['pixels/mm']) + except TypeError: + print('Error: make sure all the videos that are going to be analyzed are represented in the project_folder/logs/video_info.csv file') + fontScale = min(videoWidth, videoHeight) / (25 / fscale) + spacingScale = int(min(videoWidth, videoHeight) / (25 / space_scale)) + + ##### RECTANGLES #### + currRectangleDf = rectanglesInfo.loc[rectanglesInfo['Video'] == str(CurrVidName)] + shapeType = 'rectangle' + addSpacer = 2 + for index, row in currRectangleDf.iterrows(): + currRecName, currRecWidth,currRecHeight = (row['Name'], int(row['width']*currPixPerMM), int(row['height']*currPixPerMM)) + im = np.zeros((videoHeight, videoWidth, 3)) + cv2.putText(im, str(CurrVidName), (10, (videoHeight - videoHeight) + spacingScale), cv2.FONT_HERSHEY_SIMPLEX, fontScale,(0, 255, 0), 2) + cv2.putText(im, 'Draw rectangle: ' + str(currRecName), (10, (videoHeight - videoHeight) + spacingScale * addSpacer), cv2.FONT_HERSHEY_SIMPLEX, fontScale, (0, 255, 0), 2) + addSpacer+=1 + cv2.putText(im, 'Pre-specified size: ' + str(row['width']) + 'x' + str(row['height']) + 'mm', (10, (videoHeight - videoHeight) + spacingScale * addSpacer), cv2.FONT_HERSHEY_SIMPLEX, fontScale, (0, 255, 0), 2) + addSpacer+=1 + cv2.putText(im, 'Instructions', (10, (videoHeight - videoHeight) + spacingScale * addSpacer), cv2.FONT_HERSHEY_SIMPLEX, fontScale, (255, 255, 255), 2) + addSpacer+=1 + cv2.putText(im, str('Double left click at the top right corner of the rectangle'), (10, (videoHeight - videoHeight )+ spacingScale * addSpacer), cv2.FONT_HERSHEY_SIMPLEX, fontScale, (255, 255, 255), 2) + addSpacer+=1 + cv2.putText(im, str('Press ESC to start or to continue'), (10, (videoHeight - videoHeight) + spacingScale * addSpacer), cv2.FONT_HERSHEY_SIMPLEX, fontScale, (255, 255, 255), 2) + while (1): + cv2.imshow('Instructions', im) + k = cv2.waitKey(0) + addSpacer = 2 + if k==27: # Esc key to stop + break + + cv2.namedWindow('Define shape', cv2.WINDOW_NORMAL) + ix, iy = -1, -1 + overlay = img.copy() + topLeftStatus = False + while (1): + cv2.setMouseCallback('Define shape', draw_rectangle) + cv2.imshow('Define shape', overlay) + k = cv2.waitKey(20) + if k == 27: + boxList = [CurrVidName, shapeType, currRecName, currRecWidth, currRecHeight, topLeftX, topLeftY] + rectangularDf = rectangularDf.append(pd.Series(dict(zip(rectangularDf.columns, boxList))), ignore_index=True) + img = overlay.copy() + cv2.destroyWindow('Define shape') + break + + ##### CIRCLES #### + currCirclesDf = circleInfo.loc[circleInfo['Video'] == str(CurrVidName)] + shapeType = 'circle' + for index, row in currCirclesDf.iterrows(): + currCircleName, currCircleRadius = (row['Name'], row['Radius']*currPixPerMM) + im = np.zeros((videoHeight, videoWidth, 3)) + addSpacer += 1 + cv2.putText(im, str(CurrVidName), (10, (videoHeight - videoHeight) + spacingScale), cv2.FONT_HERSHEY_SIMPLEX, fontScale + 0.15,(144, 0, 255), 2) + addSpacer += 1 + cv2.putText(im, 'Draw circle: ' + str(currCircleName), (10, (videoHeight - videoHeight) + spacingScale * addSpacer), cv2.FONT_HERSHEY_SIMPLEX, fontScale + 0.2, (144, 0, 255), 2) + addSpacer += 1 + cv2.putText(im, 'Instructions', (10, (videoHeight - videoHeight) + spacingScale * addSpacer), cv2.FONT_HERSHEY_SIMPLEX, fontScale, (255, 255, 255), 2) + addSpacer += 1 + cv2.putText(im, str('Double left click to specify the center of the circle'), (10, (videoHeight - videoHeight) + spacingScale * addSpacer), cv2.FONT_HERSHEY_SIMPLEX, fontScale + 0.025, (255, 255, 255), 2) + addSpacer += 1 + cv2.putText(im, str('Press ESC or Enter to start or to continue'), (10, (videoHeight - videoHeight) + spacingScale * addSpacer), cv2.FONT_HERSHEY_SIMPLEX, fontScale + 0.05, (255, 255, 255), 2) + while (1): + cv2.imshow('Instructions', im) + k = cv2.waitKey(33) + if k==27: # Esc key to stop + break + overlay = img.copy() + ix, iy = -1, -1 + cv2.namedWindow('Define shape', cv2.WINDOW_NORMAL) + centerStatus = False + while (1): + cv2.setMouseCallback('Define shape',draw_circle) + cv2.imshow('Define shape', overlay) + k = cv2.waitKey(20) & 0xFF + if k == 27: + circList = [CurrVidName, shapeType, currCircleName, centerX, centerY, radius] + circleDf = circleDf.append(pd.Series(dict(zip(circleDf.columns, circList))),ignore_index=True) + img = overlay.copy() + cv2.destroyWindow('Define shape') + break + + duplicatedRec, duplicatedCirc = (rectangularDf.copy(), circleDf.copy()) + + for othervids in videofilesFound[1:]: + currVidName = os.path.splitext(os.path.basename(othervids))[0] + duplicatedRec['Video'], duplicatedCirc['Video'] = (currVidName, currVidName) + rectangularDf = rectangularDf.append(duplicatedRec, ignore_index=True) + circleDf = circleDf.append(duplicatedCirc, ignore_index=True) + + def updateImage(centroids, toRemoveShapeName): + global recWidth, recHeight, firstLoop + overlay = img.copy() + centroids = centroids.drop_duplicates() + for rectangle in range(len(currRectangleDf)): + videoName, recName, topLeftX, topLeftY = (currRectangleDf['Video'].iloc[rectangle], currRectangleDf['Name'].iloc[rectangle], currRectangleDf['topLeftX'].iloc[rectangle],currRectangleDf['topLeftY'].iloc[rectangle]) + if recName == toRemoveShapeName: + recWidth, recHeight = (currRectangleDf['width'].iloc[rectangle], currRectangleDf['height'].iloc[rectangle]) + continue + else: + bottomRightX, bottomRightY = (topLeftX + currRectangleDf['width'].iloc[rectangle], topLeftY + currRectangleDf['height'].iloc[rectangle]) + cv2.rectangle(overlay, (topLeftX, topLeftY), (bottomRightX, bottomRightY), (255, 0, 0), 10) + centerOfShape = [(topLeftX + bottomRightX) / 2, (topLeftY + bottomRightY) / 2] + cv2.circle(overlay, (int(centerOfShape[0]), int(centerOfShape[1])), 12, (255, 0, 0), -1) + if firstLoop == True: + CentroidList = [CurrVidName, 'rectangle', recName, centerOfShape[0], centerOfShape[1]] + centroids = centroids.append(pd.Series(dict(zip(centroids.columns, CentroidList))), ignore_index=True) + else: + centroids.loc[(centroids['Name'] == recName), 'CenterX'] = centerOfShape[0] + centroids.loc[(centroids['Name'] == recName), 'CenterY'] = centerOfShape[1] + correctionMask = (rectangularDf['Name'] == recName) & (rectangularDf['Video'] == videoName) + rectangularDf['topLeftX'][correctionMask], rectangularDf['topLeftY'][correctionMask] = topLeftX, topLeftY + for circle in range(len(currCirclesDf)): + videoName, circleName, centerX, centerY, radius = (currCirclesDf['Video'].iloc[circle], currCirclesDf['Name'].iloc[circle], currCirclesDf['centerX'].iloc[circle], currCirclesDf['centerY'].iloc[circle], currCirclesDf['radius'].iloc[circle]) + if circleName == toRemoveShapeName: + continue + else: + cv2.circle(overlay, (centerX, centerY), radius, (144, 0, 255), 2) + cv2.circle(overlay, (centerX, centerY), 12, (144, 0, 255), -1) + if firstLoop == True: + CentroidList = [CurrVidName, 'circle', circleName, centerX, centerY] + centroids = centroids.append(pd.Series(dict(zip(centroids.columns, CentroidList))), ignore_index=True) + else: + centroids.loc[(centroids['Name'] == circleName), 'CenterX'] = centerX + centroids.loc[(centroids['Name'] == circleName), 'CenterY'] = centerY + correctionMask = (circleDf['Name'] == circleName) & (circleDf['Video'] == videoName) + circleDf['centerX'][correctionMask], circleDf['centerY'][correctionMask] = centerX, centerY + firstLoop = False + cv2.imshow('Define shape', overlay) + return centroids + cv2.namedWindow('Define shape', cv2.WINDOW_NORMAL) + for videos in videofilesFound[1:]: + firstLoop = True + cap = cv2.VideoCapture(videos) + cap.set(1, 0) + ret, frame = cap.read() + fileName = str(0) + str('.bmp') + filePath = os.path.join(videofilesFolder, fileName) + cv2.imwrite(filePath, frame) + img = cv2.imread(filePath) + overlay = img.copy() + CurrVidName = os.path.splitext(os.path.basename(videos))[0] + currRectangleDf = rectangularDf.loc[rectanglesInfo['Video'] == str(CurrVidName)] + currCirclesDf = circleDf.loc[circleInfo['Video'] == str(CurrVidName)] + centroids = pd.DataFrame(columns=['Video', "Shape", "Name", "CenterX", "CenterY"]) + toRemoveShapeName = '' + removeStatus = True + ix, iy = -1, -1 + while (1): + centroids = updateImage(centroids, toRemoveShapeName) + if removeStatus == True: + cv2.setMouseCallback('Define shape', select_shape_to_change) + if removeStatus == False: + cv2.setMouseCallback('Define shape', select_new_shape_centroid_loc) + k = cv2.waitKey(50) & 0xFF + if k == 27: + cv2.destroyWindow('Define shape') + cv2.destroyWindow('Instructions') + break + break + + storePath = os.path.join(outPutPath, 'ROI_definitions.h5') + store = pd.HDFStore(storePath) + store['rectangles'] = rectangularDf + store['circleDf'] = circleDf + polygonDf = pd.DataFrame(columns=['Video', "Shape_type", "Name", "vertices"]) + store['polygons'] = polygonDf + print('ROI definitions saved in ' + str('storePath')) + store.close() + print(rectangularDf) + print(circleDf) print(polygonDf) \ No newline at end of file diff --git a/simba/ROI_freehand_draw_3.py b/simba/ROI_freehand_draw_3.py index eee4607dc..32465ba49 100644 --- a/simba/ROI_freehand_draw_3.py +++ b/simba/ROI_freehand_draw_3.py @@ -1,482 +1,482 @@ -from configparser import ConfigParser -import os -import cv2 -import numpy as np -import pandas as pd -from shapely.geometry import Polygon -import warnings - -def roiFreehand(inifile, currVid): - global centroids - global moveStatus - global ix, iy - global centerCordStatus - global coordChange - global insertStatus - global euclidPxDistance - global centroids, toRemoveShapeName, removeStatus, toRemoveShape - global toRemoveShapeName, removeStatus - global firstLoop - global recWidth, recHeight, firstLoop, polygonDf - global rectangularDf, circleDf, polygonDf - - - warnings.filterwarnings('ignore',category=pd.io.pytables.PerformanceWarning) - pd.options.mode.chained_assignment = None - - config = ConfigParser() - configFile = str(inifile) - config.read(configFile) - vidInfPath = config.get('General settings', 'project_path') - videofilesFolder = os.path.join(vidInfPath, "videos") - logFolderPath = os.path.join(vidInfPath, 'logs') - rectangularDf = pd.DataFrame(columns=['Video', "Shape_type", "Name", "width", "height", "topLeftX", "topLeftY"]) - circleDf = pd.DataFrame(columns=['Video', "Shape_type", "Name", "centerX", "centerY", "radius"]) - polygonDf = pd.DataFrame(columns=['Video', "Shape_type", "Name", "vertices"]) - outPutPath = os.path.join(logFolderPath, 'measures') - storePath = os.path.join(outPutPath, 'ROI_definitions.h5') - circleCordList = [] - polygonVertList = [] - - def draw_circle(event,x,y,flags,param): - global ix,iy - global centerCordStatus - if (event == cv2.EVENT_LBUTTONDBLCLK): - cv2.circle(overlay,(x,y),DrawScale,(144,0,255),-1) - cv2.imshow('Define shape', overlay) - circleCordList.append(x) - circleCordList.append(y) - if len(circleCordList) >= 3: - euclidPxDistance = int((np.sqrt((circleCordList[2] - circleCordList[0]) ** 2 + (circleCordList[3] - circleCordList[1]) ** 2))) - cv2.circle(overlay, (circleCordList[0], circleCordList[1]), int(euclidPxDistance), (144, 0, 255), DrawScale) - cv2.imshow('Define shape', overlay) - centerCordStatus = True - - def draw_polygon_vertices(event,x,y,flags,param): - global ix,iy - if (event == cv2.EVENT_LBUTTONDBLCLK): - cv2.circle(overlay,(x,y),DrawScale,(0,255,255),-1) - cv2.imshow('Define shape', overlay) - verticeTuple = (x,y) - polygonVertList.append(verticeTuple) - - def select_cord_to_change(event,x,y,flags,param): - global moveStatus - global coordChange - if (event == cv2.EVENT_LBUTTONDBLCLK): - if (x>=(circleCordList[0]-20)) and (x<=(circleCordList[0]+20)) and (y>=(circleCordList[1]-20)) and (y<=(circleCordList[1]+20)): #change point1 - coordChange = [1, circleCordList[0], circleCordList[1]] - moveStatus = True - if (x >= (circleCordList[2] - 20)) and (x <= (circleCordList[2] + 20)) and (y >= (circleCordList[3] - 20)) and (y <= (circleCordList[3] + 20)): # change point2 - coordChange = [2, circleCordList[2], circleCordList[3]] - moveStatus = True - - def select_new_dot_location(event, x, y, flags, param): - global insertStatus - global euclidPxDistance - if (event == cv2.EVENT_LBUTTONDBLCLK): - newCordList.append(x) - newCordList.append(y) - insertStatus = True - - def select_shape_to_change(event, x, y, flags, param): - global centroids, toRemoveShapeName, removeStatus, toRemoveShape - global rectangularDf, circleDf, polygonDf - if (event == cv2.EVENT_LBUTTONDBLCLK): - toRemove = centroids[(centroids['CenterX'] <= x+20) & (centroids['CenterX'] >= x-20) & (centroids['CenterY'] <= y+20) & (centroids['CenterY'] >= y-20)] - toRemoveShapeName, toRemoveShape = (toRemove["Name"].iloc[0], toRemove["Shape"].iloc[0]) - updateImage(centroids, toRemoveShapeName, rectangularDf, circleDf, polygonDf) - removeStatus = False - - def select_new_shape_centroid_loc(event, x, y, flags, param): - global toRemoveShapeName, removeStatus - global rectangularDf, circleDf, polygonDf - newVertices = [] - if (event == cv2.EVENT_LBUTTONDBLCLK): - toInsertShapeName, toInsertShape = toRemoveShapeName, toRemoveShape - toRemoveShapeName = '' - if toInsertShape == 'rectangle': - newTopLeftX, newTopLeftY = (int(x -(recWidth/2)), int((y -(recHeight/2)))) - rectangularDf.loc[(rectangularDf['Name'] == toInsertShapeName), 'topLeftX'] = newTopLeftX - rectangularDf.loc[(rectangularDf['Name'] == toInsertShapeName), 'topLeftY'] = newTopLeftY - if toInsertShape == 'circle': - newcenterX, newcenterY = (int(x), int(y)) - circleDf.loc[(circleDf['Name'] == toInsertShapeName), 'centerX'] = newcenterX - circleDf.loc[(circleDf['Name'] == toInsertShapeName), 'centerY'] = newcenterY - if toInsertShape == 'polygon': - newPolyCentroidX, newPolyCentroidY = (int(x), int(y)) - OldCentroidX = int(centroids.loc[(centroids['Name'] == toInsertShapeName), 'CenterX'].unique()) - OldCentroidY = int(centroids.loc[(centroids['Name'] == toInsertShapeName), 'CenterY'].unique()) - verticeDifferenceX = OldCentroidX - (newPolyCentroidX) - verticeDifferenceY = OldCentroidY - (newPolyCentroidY) - oldVertices = polygonDf.loc[(polygonDf['Name'] == toInsertShapeName), 'vertices'] - oldVertices = [num for elem in oldVertices for num in elem] - oldVerticeX = [item[0] for item in oldVertices] - oldVerticeY = [item[1] for item in oldVertices] - newX = [ppp - verticeDifferenceX for ppp in oldVerticeX] - newY = [ppp - verticeDifferenceY for ppp in oldVerticeY] - for i in range(len(newX)): - coord = [newX[i], newY[i]] - newVertices.append(coord) - polygonDf.loc[(polygonDf['Name'] == toInsertShapeName), 'vertices'] = [newVertices] - removeStatus = True - updateImage(centroids, toRemoveShapeName, rectangularDf, circleDf, polygonDf) - - - cap = cv2.VideoCapture(currVid) - cap.set(1, 0) - ret, frame = cap.read() - fileName = str(0) + str('.bmp') - filePath = os.path.join(videofilesFolder, fileName) - cv2.imwrite(filePath,frame) - img = cv2.imread(filePath) - DrawScale = int(max(img.shape[0], img.shape[1]) / 120) - print(DrawScale) - textScale = min(img.shape[0], img.shape[1]) / 1500 - print(textScale) - - - CurrVidName = os.path.basename(currVid).replace('.mp4', '') - instructionHeight, instructionWidth = (400, 1000) - ROIcoordinatesPath = os.path.join(logFolderPath, 'measures', 'ROI_definitions.h5') - - ### CHECK IF ROI DEFINITIONS EXIST - try: - rectanglesInfo = pd.read_hdf(ROIcoordinatesPath, key='rectangles') - circleInfo = pd.read_hdf(ROIcoordinatesPath, key='circleDf') - polygonInfo = pd.read_hdf(ROIcoordinatesPath, key='polygons') - rectangularDf = rectanglesInfo.loc[rectanglesInfo['Video'] == str(CurrVidName)] - circleDf = circleInfo.loc[circleInfo['Video'] == str(CurrVidName)] - polygonDf = polygonInfo.loc[polygonInfo['Video'] == str(CurrVidName)] - inputRect, inputCirc, inputPoly = (rectanglesInfo.copy(), circleInfo.copy(), polygonInfo.copy()) - inputRect, inputCirc, inputPoly = (inputRect[inputRect["Video"] != CurrVidName], inputCirc[inputCirc["Video"] != CurrVidName], inputPoly[inputPoly["Video"] != CurrVidName]) - ROIdefExist = True - except FileNotFoundError: - ROIdefExist = False - vidROIDefs = False - inputRect = pd.DataFrame(columns=['Video', "Shape_type", "Name", "width", "height", "topLeftX", "topLeftY"]) - inputCirc = pd.DataFrame(columns=['Video', "Shape_type", "Name", "centerX", "centerY", "radius"]) - inputPoly = pd.DataFrame(columns=['Video', "Shape_type", "Name", "vertices"]) - - ### CHECK IF CURRENT VIDEO DEFINITIONS EXIST - if ROIdefExist is True: - if (len(rectangularDf) == 0 and len(circleDf) == 0 and len(polygonDf) == 0): - vidROIDefs = False - else: - vidROIDefs = True - - if (ROIdefExist is False) or (vidROIDefs is False): - ROIindexPath = os.path.join(logFolderPath, 'measures', 'ROI_index.h5') - rect2Draw = pd.read_hdf(ROIindexPath, key='rectangles') - circ2Draw = pd.read_hdf(ROIindexPath, key='circleDf') - pol2draw = pd.read_hdf(ROIindexPath, key='polygons') - ##### RECTANGLES #### - for index, row in rect2Draw.iterrows(): - shapeType = 'rectangle' - currRectangleName = row['Name'] - im = np.zeros((instructionHeight, instructionWidth, 3)) - cv2.putText(im, str(CurrVidName), (10, 20), cv2.FONT_HERSHEY_SIMPLEX, 0.7,(0, 255, 0), 2) - cv2.putText(im, 'Draw rectangle: ' + str(currRectangleName), (10, 60), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2) - cv2.putText(im, 'Instructions', (10, 110), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2) - cv2.putText(im, str('Press and hold left mouse button at the top right corner of the rectangle ROI'), (10, 160), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2) - cv2.putText(im, str('Drag the mouse to the bottom right corner of the rectangle ROI'), (10, 210), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2) - cv2.putText(im, 'Repeat this to redo the rectangle "' + str(currRectangleName) + '" ROI', (10, 270), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2) - cv2.putText(im, str('Press ESC to start, and press ESC twice when happy with rectangle "' + str(currRectangleName) + '" ROI'), (10, 320), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2) - while (1): - cv2.imshow('Instructions', im) - k = cv2.waitKey(0) - if k==27: # Esc key to stop - break - - cv2.namedWindow('Define shape', cv2.WINDOW_NORMAL) - while (1): - ROI = cv2.selectROI('Define shape', img) - width = (abs(ROI[0] - (ROI[2] + ROI[0]))) - height = (abs(ROI[2] - (ROI[3] + ROI[2]))) - topLeftX = ROI[0] - topLeftY = ROI[1] - cv2.rectangle(img, (topLeftX, topLeftY), (topLeftX+width, topLeftY+height), (255, 0, 0), DrawScale) - k = cv2.waitKey(0) - boxList = [CurrVidName, shapeType, currRectangleName, width, height, topLeftX, topLeftY] - if (k == 27) or (k==47): # Esc key to stop - rectangularDf = rectangularDf.append(pd.Series(dict(zip(rectangularDf.columns, boxList))), ignore_index=True) - cv2.destroyWindow('Define shape') - break - - ##### CIRCLES #### - for index, row in circ2Draw.iterrows(): - shapeType = 'circle' - centerCordStatus = False - moveStatus = False - insertStatus = False - changeLoop = False - centerCordStatus = False - currCircleName = row['Name'] - im = np.zeros((550, 1000, 3)) - cv2.putText(im, str(CurrVidName), (10, 20), cv2.FONT_HERSHEY_SIMPLEX, 0.7,(144, 0, 255), 2) - cv2.putText(im, 'Draw circle: ' + str(currCircleName), (10, 60), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (144, 0, 255), 2) - cv2.putText(im, 'Instructions', (10,110), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2) - cv2.putText(im, str('Double left click to specify the center of the circle'), (10, 160), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2) - cv2.putText(im, str('Next, double left click to specify the outer bounds of the circle'), (10, 210), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2) - cv2.putText(im, str('To change circle center location, first double left click on the circle center,'), (10, 260), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255,255), 2) - cv2.putText(im, str('and then double left click in the new center location.'), (10, 310), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2) - cv2.putText(im, str('To change circle radius, first double left click on the circle outer bound,'), (10, 360), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2) - cv2.putText(im, str('and then double left click at the new circle outer bound.'), (10, 410), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2) - cv2.putText(im, str('Press ESC or Enter to start or to continue'), (10, 460), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2) - while (1): - cv2.imshow('Instructions', im) - k = cv2.waitKey(33) - if k==27: - break - overlay = img.copy() - origImage = img.copy() - circleCordList = newCordList = [] - ix, iy = -1, -1 - - cv2.namedWindow('Define shape', cv2.WINDOW_NORMAL) - while (1): - if centerCordStatus == False and (moveStatus == False) and (insertStatus == False): - cv2.setMouseCallback('Define shape',draw_circle) - cv2.imshow('Define shape', overlay) - k = cv2.waitKey(20) & 0xFF - if k == 27: - break - if centerCordStatus == True and (moveStatus == False) and (insertStatus == False): - if changeLoop == True: - overlay = origImage.copy() - cv2.circle(overlay, (circleCordList[0], circleCordList[1]), DrawScale, (144, 0, 255), -1) - cv2.circle(overlay, (circleCordList[2], circleCordList[3]), DrawScale, (144, 0, 255), -1) - cv2.circle(overlay, (circleCordList[0], circleCordList[1]), euclidPxDistance, (144, 0, 255), DrawScale) - euclidPxDistance = int((np.sqrt((circleCordList[2] - circleCordList[0]) ** 2 + (circleCordList[3] - circleCordList[1]) ** 2))) - circleCordAppend = [CurrVidName, shapeType, currCircleName, circleCordList[0], circleCordList[1], euclidPxDistance] - cv2.imshow('Define shape', overlay) - cv2.setMouseCallback('Define shape', select_cord_to_change) - if (moveStatus == True) and (insertStatus == False): - if changeLoop == True: - img = origImage.copy() - changeLoop = False - if coordChange[0] == 1: - cv2.circle(img, (circleCordList[2], circleCordList[3]), DrawScale, (144, 0, 255), -1) - if coordChange[0] == 2: - cv2.circle(img, (circleCordList[0], circleCordList[1]), DrawScale, (144, 0, 255), -1) - euclidPxDistance = int((np.sqrt((circleCordList[2] - circleCordList[0]) ** 2 + (circleCordList[3] - circleCordList[1]) ** 2))) - cv2.circle(img, (circleCordList[0], circleCordList[1]), euclidPxDistance, (144, 0, 255), DrawScale) - circleCordAppend = [CurrVidName, shapeType, currCircleName, circleCordList[0], circleCordList[1], euclidPxDistance] - cv2.imshow('Define shape', img) - cv2.setMouseCallback('Define shape', select_new_dot_location) - if (insertStatus == True): - if coordChange[0] == 1: - cv2.circle(img, (circleCordList[2], circleCordList[3]), DrawScale, (144, 0, 255), -1) - cv2.circle(img, (newCordList[-2], newCordList[-1]), DrawScale, (144, 0, 255), -1) - cv2.circle(img, (circleCordList[0], circleCordList[1]), euclidPxDistance, (144, 0, 255), DrawScale) - circleCordList = [newCordList[-2], newCordList[-1], circleCordList[2], circleCordList[3]] - circleCordAppend = [CurrVidName, shapeType, currCircleName, circleCordList[0], circleCordList[1],euclidPxDistance] - centerCordStatus = True - moveStatus = False - insertStatus = False - changeLoop = True - if coordChange[0] == 2: - cv2.circle(img, (circleCordList[0], circleCordList[1]), DrawScale, (144, 0, 255), -1) - cv2.circle(img, (newCordList[-2], newCordList[-1]), DrawScale, (144, 0, 255), -1) - euclidPxDistance = int((np.sqrt((circleCordList[1] - newCordList[-1]) ** 2 + (circleCordList[0] - newCordList[-2]) ** 2))) - cv2.circle(img, (circleCordList[0], circleCordList[1]), euclidPxDistance, (144, 0, 255), DrawScale) - circleCordList = [circleCordList[0], circleCordList[1], newCordList[-2], newCordList[-1]] - circleCordAppend = [CurrVidName, shapeType, currCircleName, circleCordList[0], circleCordList[1], euclidPxDistance] - centerCordStatus = True - moveStatus = False - insertStatus = False - changeLoop = True - cv2.imshow('Define shape', img) - img = overlay.copy() - k = cv2.waitKey(20) & 0xFF - if k == 27: - circleDf = circleDf.append(pd.Series(dict(zip(circleDf.columns, circleCordAppend))), ignore_index=True) - cv2.destroyWindow('Define shape') - break - - ##### POLYGONS #### - for index, row in pol2draw.iterrows(): - currPolygonName = row['Name'] - shapeType = 'polygon' - im = np.zeros((550, 1000, 3)) - cv2.putText(im, str(CurrVidName), (10, 20), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 255), 2) - cv2.putText(im, 'Draw polygon: ' + str(currPolygonName), (10, 60), cv2.FONT_HERSHEY_SIMPLEX, 0.7 + 0.2, (0, 255, 255), 2) - cv2.putText(im, 'Instructions', (10, 110), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2) - cv2.putText(im, str('Double left click at at least 3 outer bounds of the polygon'), (10, 160), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2) - cv2.putText(im, str('Press ESC start or to continue'), (10, 210), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2) - while (1): - cv2.imshow('Instructions', im) - k = cv2.waitKey(0) - if k==27: - break - overlay = img.copy() - polyGonListOfLists = [] - polygonVertList = [] - cv2.namedWindow('Define shape', cv2.WINDOW_NORMAL) - while (1): - cv2.setMouseCallback('Define shape', draw_polygon_vertices) - cv2.imshow('Define shape', overlay) - k = cv2.waitKey(0) & 0xFF - if k == 27: - if len(polygonVertList) >= 3: - break - else: - pass - # break - #break - polyGon = Polygon(polygonVertList) - polyX, polyY = polyGon.exterior.coords.xy - for i in range(len(polyX)): - polyGonListOfLists.append([polyX[i], polyY[i]]) - polyGonListtoDf = [CurrVidName, shapeType, currPolygonName, polyGonListOfLists] - polyGonListOfLists = np.array(polyGonListOfLists, np.int32) - polyGonListOfLists = polyGonListOfLists.reshape((-1, 1, 2)) - polyLine = cv2.convexHull(polyGonListOfLists) - cv2.drawContours(overlay, [polyLine.astype(int)], 0, (0, 255, 255), DrawScale) - cv2.imshow('Define shape', overlay) - polygonDf = polygonDf.append(pd.Series(dict(zip(polygonDf.columns, polyGonListtoDf))), ignore_index=True) - img = overlay.copy() - cv2.imshow('Define shape', overlay) - k = cv2.waitKey(0) & 0xFF - if k == 27: # Esc key to stop - cv2.destroyWindow('Define shape') - cv2.destroyWindow('Instructions') - # break - # break - cv2.destroyWindow('Define shape') - cv2.destroyWindow('Instructions') - storePath = os.path.join(outPutPath, 'ROI_definitions.h5') - store = pd.HDFStore(storePath, mode='w') - rec = pd.concat([rectangularDf, inputRect], ignore_index=True, sort=False) - circ = pd.concat([circleDf, inputCirc], ignore_index=True, sort=False) - polyg = pd.concat([polygonDf, inputPoly], ignore_index=True, sort=False) - store['rectangles'] = rec - store['circleDf'] = circ - store['polygons'] = polyg - print('ROI definitions saved in ' + str(storePath)) - print('ROI definitions saved in ' + 'project_folder\logs\measures\ROI_definitions.h5') - store.close() - - delImagePath = os.path.join(videofilesFolder, '0.bmp') - os.remove(delImagePath) - - def updateImage(centroids, toRemoveShapeName, rectangularDf, circleDf, polygonDf): - global recWidth, recHeight, firstLoop - overlay = img.copy() - centroids = centroids.drop_duplicates() - for rectangle in range(len(rectangularDf)): - videoName, recName, topLeftX, topLeftY = (rectangularDf['Video'].iloc[rectangle], rectangularDf['Name'].iloc[rectangle], rectangularDf['topLeftX'].iloc[rectangle],rectangularDf['topLeftY'].iloc[rectangle]) - if recName == toRemoveShapeName: - recWidth, recHeight = (rectangularDf['width'].iloc[rectangle], rectangularDf['height'].iloc[rectangle]) - continue - else: - bottomRightX, bottomRightY = (topLeftX + rectangularDf['width'].iloc[rectangle], topLeftY + rectangularDf['height'].iloc[rectangle]) - cv2.rectangle(overlay, (topLeftX, topLeftY), (bottomRightX, bottomRightY), (255, 0, 0), DrawScale) - centerOfShape = [(topLeftX + bottomRightX) / 2, (topLeftY + bottomRightY) / 2] - cv2.circle(overlay, (int(centerOfShape[0]), int(centerOfShape[1])),DrawScale, (255, 0, 0), -1) - if firstLoop == True: - CentroidList = [CurrVidName, 'rectangle', recName, centerOfShape[0], centerOfShape[1]] - centroids = centroids.append(pd.Series(dict(zip(centroids.columns, CentroidList))), ignore_index=True) - else: - centroids.loc[(centroids['Name'] == recName), 'CenterX'] = centerOfShape[0] - centroids.loc[(centroids['Name'] == recName), 'CenterY'] = centerOfShape[1] - correctionMask = (rectangularDf['Name'] == recName) & (rectangularDf['Video'] == videoName) - rectangularDf['topLeftX'][correctionMask], rectangularDf['topLeftY'][correctionMask] = topLeftX, topLeftY - #recListtoDf = [videoName, "ractangle", recName, recWidth, recHeight, topLeftX, topLeftY] - #rectangularDf = rectangularDf.append(pd.Series(dict(zip(rectangularDf.columns, recListtoDf))), ignore_index=True) - for circle in range(len(circleDf)): - videoName, circleName, centerX, centerY, radius = (circleDf['Video'].iloc[circle], circleDf['Name'].iloc[circle], circleDf['centerX'].iloc[circle], circleDf['centerY'].iloc[circle], circleDf['radius'].iloc[circle]) - if circleName == toRemoveShapeName: - continue - else: - cv2.circle(overlay, (centerX, centerY), radius, (144, 0, 255), DrawScale) - cv2.circle(overlay, (centerX, centerY), DrawScale, (144, 0, 255), -1) - if firstLoop == True: - CentroidList = [CurrVidName, 'circle', circleName, centerX, centerY] - centroids = centroids.append(pd.Series(dict(zip(centroids.columns, CentroidList))), ignore_index=True) - else: - centroids.loc[(centroids['Name'] == circleName), 'CenterX'] = centerX - centroids.loc[(centroids['Name'] == circleName), 'CenterY'] = centerY - correctionMask = (circleDf['Name'] == circleName) & (circleDf['Video'] == videoName) - circleDf['centerX'][correctionMask], circleDf['centerY'][correctionMask] = centerX, centerY - #for polygon in range(len(polygonDf)): - for index, row in polygonDf.iterrows(): - videoName, polyName, inputVertices = (row['Video'], row['Name'], row['vertices']) - if polyName == toRemoveShapeName: - continue - else: - sumofX, sumofY = (int(sum([item[0] for item in inputVertices])), int(sum([item[1] for item in inputVertices]))) - PolyCentroidX, PolyCentroidY = (int(sumofX / len(inputVertices)), int(sumofY / len(inputVertices))) - cv2.circle(overlay, (PolyCentroidX, PolyCentroidY), DrawScale, (0,255,255), -1) - vertices = np.array(inputVertices, np.int32) - cv2.polylines(overlay, [vertices], True, (0, 255, 255), thickness=DrawScale) - if firstLoop == True: - CentroidList = [CurrVidName, 'polygon', polyName, PolyCentroidX, PolyCentroidY] - centroids = centroids.append(pd.Series(dict(zip(centroids.columns, CentroidList))), ignore_index=True) - else: - centroids.loc[(centroids['Name'] == polyName), 'CenterX'] = PolyCentroidX - centroids.loc[(centroids['Name'] == polyName), 'CenterY'] = PolyCentroidY - polygonDf = polygonDf.drop(polygonDf[(polygonDf['Video'] == videoName) & (polygonDf['Name'] == polyName)].index) - polyGonListtoDf = [videoName, 'polygon', polyName, inputVertices] - polygonDf = polygonDf.append(pd.Series(dict(zip(polygonDf.columns, polyGonListtoDf))), ignore_index=True) - firstLoop = False - cv2.imshow('Define shape', overlay) - return centroids - - if (ROIdefExist is True) and (vidROIDefs is True): - firstLoop = True - cap = cv2.VideoCapture(currVid) - cap.set(1, 0) - ret, frame = cap.read() - fileName = str(0) + str('.bmp') - filePath = os.path.join(videofilesFolder, fileName) - cv2.imwrite(filePath, frame) - img = cv2.imread(filePath) - overlay = img.copy() - CurrVidName = os.path.basename(currVid).replace('.mp4', '') - centroids = pd.DataFrame(columns=['Video', "Shape", "Name", "CenterX", "CenterY"]) - toRemoveShapeName = '' - removeStatus = True - ix, iy = -1, -1 - im = np.zeros((400, 1000, 3)) - cv2.putText(im, 'Move shapes for ' + str(CurrVidName), (10, 20), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 255), 2) - cv2.putText(im, 'Instructions', (10, 60), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2) - cv2.putText(im, str('Double left click on the centroid of the shape you wish to move'), (10, 110), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2) - cv2.putText(im, str('Then double click in the new centroid location'), (10, 160), cv2.FONT_HERSHEY_SIMPLEX,0.7, (255, 255, 255), 2) - cv2.putText(im, str('Press ESC to start and when finished'), (10, 210), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2) - while (1): - cv2.imshow('Instructions', im) - k = cv2.waitKey(0) - if k == 27: # Esc key to stop - break - while (1): - cv2.namedWindow('Define shape', cv2.WINDOW_NORMAL) - centroids = updateImage(centroids, toRemoveShapeName, rectangularDf, circleDf, polygonDf) - if removeStatus == True: - cv2.setMouseCallback('Define shape', select_shape_to_change) - if removeStatus == False: - cv2.setMouseCallback('Define shape', select_new_shape_centroid_loc) - k = cv2.waitKey(50) & 0xFF - if k == 27: - cv2.destroyWindow('Define shape') - cv2.destroyWindow('Instructions') - break - cv2.destroyWindow('Define shape') - cv2.destroyWindow('Instructions') - store = pd.HDFStore(storePath, mode='w') - rec = pd.concat([rectangularDf, inputRect], ignore_index=True, sort=False) - circ = pd.concat([circleDf, inputCirc], ignore_index=True, sort=False) - polyg = pd.concat([polygonDf, inputPoly], ignore_index=True, sort=False) - store['rectangles'] = rec - store['circleDf'] = circ - store['polygons'] = polyg - print('ROI definitions saved in ' + 'project_folder\logs\measures\ROI_definitions.h5') - store.close() - - delImagePath = os.path.join(videofilesFolder, '0.bmp') - os.remove(delImagePath) - - - - - +from configparser import ConfigParser +import os +import cv2 +import numpy as np +import pandas as pd +from shapely.geometry import Polygon +import warnings + +def roiFreehand(inifile, currVid): + global centroids + global moveStatus + global ix, iy + global centerCordStatus + global coordChange + global insertStatus + global euclidPxDistance + global centroids, toRemoveShapeName, removeStatus, toRemoveShape + global toRemoveShapeName, removeStatus + global firstLoop + global recWidth, recHeight, firstLoop, polygonDf + global rectangularDf, circleDf, polygonDf + + + warnings.filterwarnings('ignore',category=pd.io.pytables.PerformanceWarning) + pd.options.mode.chained_assignment = None + + config = ConfigParser() + configFile = str(inifile) + config.read(configFile) + vidInfPath = config.get('General settings', 'project_path') + videofilesFolder = os.path.join(vidInfPath, "videos") + logFolderPath = os.path.join(vidInfPath, 'logs') + rectangularDf = pd.DataFrame(columns=['Video', "Shape_type", "Name", "width", "height", "topLeftX", "topLeftY"]) + circleDf = pd.DataFrame(columns=['Video', "Shape_type", "Name", "centerX", "centerY", "radius"]) + polygonDf = pd.DataFrame(columns=['Video', "Shape_type", "Name", "vertices"]) + outPutPath = os.path.join(logFolderPath, 'measures') + storePath = os.path.join(outPutPath, 'ROI_definitions.h5') + circleCordList = [] + polygonVertList = [] + + def draw_circle(event,x,y,flags,param): + global ix,iy + global centerCordStatus + if (event == cv2.EVENT_LBUTTONDBLCLK): + cv2.circle(overlay,(x,y),DrawScale,(144,0,255),-1) + cv2.imshow('Define shape', overlay) + circleCordList.append(x) + circleCordList.append(y) + if len(circleCordList) >= 3: + euclidPxDistance = int((np.sqrt((circleCordList[2] - circleCordList[0]) ** 2 + (circleCordList[3] - circleCordList[1]) ** 2))) + cv2.circle(overlay, (circleCordList[0], circleCordList[1]), int(euclidPxDistance), (144, 0, 255), DrawScale) + cv2.imshow('Define shape', overlay) + centerCordStatus = True + + def draw_polygon_vertices(event,x,y,flags,param): + global ix,iy + if (event == cv2.EVENT_LBUTTONDBLCLK): + cv2.circle(overlay,(x,y),DrawScale,(0,255,255),-1) + cv2.imshow('Define shape', overlay) + verticeTuple = (x,y) + polygonVertList.append(verticeTuple) + + def select_cord_to_change(event,x,y,flags,param): + global moveStatus + global coordChange + if (event == cv2.EVENT_LBUTTONDBLCLK): + if (x>=(circleCordList[0]-20)) and (x<=(circleCordList[0]+20)) and (y>=(circleCordList[1]-20)) and (y<=(circleCordList[1]+20)): #change point1 + coordChange = [1, circleCordList[0], circleCordList[1]] + moveStatus = True + if (x >= (circleCordList[2] - 20)) and (x <= (circleCordList[2] + 20)) and (y >= (circleCordList[3] - 20)) and (y <= (circleCordList[3] + 20)): # change point2 + coordChange = [2, circleCordList[2], circleCordList[3]] + moveStatus = True + + def select_new_dot_location(event, x, y, flags, param): + global insertStatus + global euclidPxDistance + if (event == cv2.EVENT_LBUTTONDBLCLK): + newCordList.append(x) + newCordList.append(y) + insertStatus = True + + def select_shape_to_change(event, x, y, flags, param): + global centroids, toRemoveShapeName, removeStatus, toRemoveShape + global rectangularDf, circleDf, polygonDf + if (event == cv2.EVENT_LBUTTONDBLCLK): + toRemove = centroids[(centroids['CenterX'] <= x+20) & (centroids['CenterX'] >= x-20) & (centroids['CenterY'] <= y+20) & (centroids['CenterY'] >= y-20)] + toRemoveShapeName, toRemoveShape = (toRemove["Name"].iloc[0], toRemove["Shape"].iloc[0]) + updateImage(centroids, toRemoveShapeName, rectangularDf, circleDf, polygonDf) + removeStatus = False + + def select_new_shape_centroid_loc(event, x, y, flags, param): + global toRemoveShapeName, removeStatus + global rectangularDf, circleDf, polygonDf + newVertices = [] + if (event == cv2.EVENT_LBUTTONDBLCLK): + toInsertShapeName, toInsertShape = toRemoveShapeName, toRemoveShape + toRemoveShapeName = '' + if toInsertShape == 'rectangle': + newTopLeftX, newTopLeftY = (int(x -(recWidth/2)), int((y -(recHeight/2)))) + rectangularDf.loc[(rectangularDf['Name'] == toInsertShapeName), 'topLeftX'] = newTopLeftX + rectangularDf.loc[(rectangularDf['Name'] == toInsertShapeName), 'topLeftY'] = newTopLeftY + if toInsertShape == 'circle': + newcenterX, newcenterY = (int(x), int(y)) + circleDf.loc[(circleDf['Name'] == toInsertShapeName), 'centerX'] = newcenterX + circleDf.loc[(circleDf['Name'] == toInsertShapeName), 'centerY'] = newcenterY + if toInsertShape == 'polygon': + newPolyCentroidX, newPolyCentroidY = (int(x), int(y)) + OldCentroidX = int(centroids.loc[(centroids['Name'] == toInsertShapeName), 'CenterX'].unique()) + OldCentroidY = int(centroids.loc[(centroids['Name'] == toInsertShapeName), 'CenterY'].unique()) + verticeDifferenceX = OldCentroidX - (newPolyCentroidX) + verticeDifferenceY = OldCentroidY - (newPolyCentroidY) + oldVertices = polygonDf.loc[(polygonDf['Name'] == toInsertShapeName), 'vertices'] + oldVertices = [num for elem in oldVertices for num in elem] + oldVerticeX = [item[0] for item in oldVertices] + oldVerticeY = [item[1] for item in oldVertices] + newX = [ppp - verticeDifferenceX for ppp in oldVerticeX] + newY = [ppp - verticeDifferenceY for ppp in oldVerticeY] + for i in range(len(newX)): + coord = [newX[i], newY[i]] + newVertices.append(coord) + polygonDf.loc[(polygonDf['Name'] == toInsertShapeName), 'vertices'] = [newVertices] + removeStatus = True + updateImage(centroids, toRemoveShapeName, rectangularDf, circleDf, polygonDf) + + + cap = cv2.VideoCapture(currVid) + cap.set(1, 0) + ret, frame = cap.read() + fileName = str(0) + str('.bmp') + filePath = os.path.join(videofilesFolder, fileName) + cv2.imwrite(filePath,frame) + img = cv2.imread(filePath) + DrawScale = int(max(img.shape[0], img.shape[1]) / 120) + print(DrawScale) + textScale = min(img.shape[0], img.shape[1]) / 1500 + print(textScale) + + + CurrVidName = os.path.splitext(os.path.basename(currVid))[0] + instructionHeight, instructionWidth = (400, 1000) + ROIcoordinatesPath = os.path.join(logFolderPath, 'measures', 'ROI_definitions.h5') + + ### CHECK IF ROI DEFINITIONS EXIST + try: + rectanglesInfo = pd.read_hdf(ROIcoordinatesPath, key='rectangles') + circleInfo = pd.read_hdf(ROIcoordinatesPath, key='circleDf') + polygonInfo = pd.read_hdf(ROIcoordinatesPath, key='polygons') + rectangularDf = rectanglesInfo.loc[rectanglesInfo['Video'] == str(CurrVidName)] + circleDf = circleInfo.loc[circleInfo['Video'] == str(CurrVidName)] + polygonDf = polygonInfo.loc[polygonInfo['Video'] == str(CurrVidName)] + inputRect, inputCirc, inputPoly = (rectanglesInfo.copy(), circleInfo.copy(), polygonInfo.copy()) + inputRect, inputCirc, inputPoly = (inputRect[inputRect["Video"] != CurrVidName], inputCirc[inputCirc["Video"] != CurrVidName], inputPoly[inputPoly["Video"] != CurrVidName]) + ROIdefExist = True + except FileNotFoundError: + ROIdefExist = False + vidROIDefs = False + inputRect = pd.DataFrame(columns=['Video', "Shape_type", "Name", "width", "height", "topLeftX", "topLeftY"]) + inputCirc = pd.DataFrame(columns=['Video', "Shape_type", "Name", "centerX", "centerY", "radius"]) + inputPoly = pd.DataFrame(columns=['Video', "Shape_type", "Name", "vertices"]) + + ### CHECK IF CURRENT VIDEO DEFINITIONS EXIST + if ROIdefExist is True: + if (len(rectangularDf) == 0 and len(circleDf) == 0 and len(polygonDf) == 0): + vidROIDefs = False + else: + vidROIDefs = True + + if (ROIdefExist is False) or (vidROIDefs is False): + ROIindexPath = os.path.join(logFolderPath, 'measures', 'ROI_index.h5') + rect2Draw = pd.read_hdf(ROIindexPath, key='rectangles') + circ2Draw = pd.read_hdf(ROIindexPath, key='circleDf') + pol2draw = pd.read_hdf(ROIindexPath, key='polygons') + ##### RECTANGLES #### + for index, row in rect2Draw.iterrows(): + shapeType = 'rectangle' + currRectangleName = row['Name'] + im = np.zeros((instructionHeight, instructionWidth, 3)) + cv2.putText(im, str(CurrVidName), (10, 20), cv2.FONT_HERSHEY_SIMPLEX, 0.7,(0, 255, 0), 2) + cv2.putText(im, 'Draw rectangle: ' + str(currRectangleName), (10, 60), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2) + cv2.putText(im, 'Instructions', (10, 110), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2) + cv2.putText(im, str('Press and hold left mouse button at the top right corner of the rectangle ROI'), (10, 160), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2) + cv2.putText(im, str('Drag the mouse to the bottom right corner of the rectangle ROI'), (10, 210), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2) + cv2.putText(im, 'Repeat this to redo the rectangle "' + str(currRectangleName) + '" ROI', (10, 270), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2) + cv2.putText(im, str('Press ESC to start, and press ESC twice when happy with rectangle "' + str(currRectangleName) + '" ROI'), (10, 320), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2) + while (1): + cv2.imshow('Instructions', im) + k = cv2.waitKey(0) + if k==27: # Esc key to stop + break + + cv2.namedWindow('Define shape', cv2.WINDOW_NORMAL) + while (1): + ROI = cv2.selectROI('Define shape', img) + width = (abs(ROI[0] - (ROI[2] + ROI[0]))) + height = (abs(ROI[2] - (ROI[3] + ROI[2]))) + topLeftX = ROI[0] + topLeftY = ROI[1] + cv2.rectangle(img, (topLeftX, topLeftY), (topLeftX+width, topLeftY+height), (255, 0, 0), DrawScale) + k = cv2.waitKey(0) + boxList = [CurrVidName, shapeType, currRectangleName, width, height, topLeftX, topLeftY] + if (k == 27) or (k==47): # Esc key to stop + rectangularDf = rectangularDf.append(pd.Series(dict(zip(rectangularDf.columns, boxList))), ignore_index=True) + cv2.destroyWindow('Define shape') + break + + ##### CIRCLES #### + for index, row in circ2Draw.iterrows(): + shapeType = 'circle' + centerCordStatus = False + moveStatus = False + insertStatus = False + changeLoop = False + centerCordStatus = False + currCircleName = row['Name'] + im = np.zeros((550, 1000, 3)) + cv2.putText(im, str(CurrVidName), (10, 20), cv2.FONT_HERSHEY_SIMPLEX, 0.7,(144, 0, 255), 2) + cv2.putText(im, 'Draw circle: ' + str(currCircleName), (10, 60), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (144, 0, 255), 2) + cv2.putText(im, 'Instructions', (10,110), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2) + cv2.putText(im, str('Double left click to specify the center of the circle'), (10, 160), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2) + cv2.putText(im, str('Next, double left click to specify the outer bounds of the circle'), (10, 210), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2) + cv2.putText(im, str('To change circle center location, first double left click on the circle center,'), (10, 260), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255,255), 2) + cv2.putText(im, str('and then double left click in the new center location.'), (10, 310), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2) + cv2.putText(im, str('To change circle radius, first double left click on the circle outer bound,'), (10, 360), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2) + cv2.putText(im, str('and then double left click at the new circle outer bound.'), (10, 410), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2) + cv2.putText(im, str('Press ESC or Enter to start or to continue'), (10, 460), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2) + while (1): + cv2.imshow('Instructions', im) + k = cv2.waitKey(33) + if k==27: + break + overlay = img.copy() + origImage = img.copy() + circleCordList = newCordList = [] + ix, iy = -1, -1 + + cv2.namedWindow('Define shape', cv2.WINDOW_NORMAL) + while (1): + if centerCordStatus == False and (moveStatus == False) and (insertStatus == False): + cv2.setMouseCallback('Define shape',draw_circle) + cv2.imshow('Define shape', overlay) + k = cv2.waitKey(20) & 0xFF + if k == 27: + break + if centerCordStatus == True and (moveStatus == False) and (insertStatus == False): + if changeLoop == True: + overlay = origImage.copy() + cv2.circle(overlay, (circleCordList[0], circleCordList[1]), DrawScale, (144, 0, 255), -1) + cv2.circle(overlay, (circleCordList[2], circleCordList[3]), DrawScale, (144, 0, 255), -1) + cv2.circle(overlay, (circleCordList[0], circleCordList[1]), euclidPxDistance, (144, 0, 255), DrawScale) + euclidPxDistance = int((np.sqrt((circleCordList[2] - circleCordList[0]) ** 2 + (circleCordList[3] - circleCordList[1]) ** 2))) + circleCordAppend = [CurrVidName, shapeType, currCircleName, circleCordList[0], circleCordList[1], euclidPxDistance] + cv2.imshow('Define shape', overlay) + cv2.setMouseCallback('Define shape', select_cord_to_change) + if (moveStatus == True) and (insertStatus == False): + if changeLoop == True: + img = origImage.copy() + changeLoop = False + if coordChange[0] == 1: + cv2.circle(img, (circleCordList[2], circleCordList[3]), DrawScale, (144, 0, 255), -1) + if coordChange[0] == 2: + cv2.circle(img, (circleCordList[0], circleCordList[1]), DrawScale, (144, 0, 255), -1) + euclidPxDistance = int((np.sqrt((circleCordList[2] - circleCordList[0]) ** 2 + (circleCordList[3] - circleCordList[1]) ** 2))) + cv2.circle(img, (circleCordList[0], circleCordList[1]), euclidPxDistance, (144, 0, 255), DrawScale) + circleCordAppend = [CurrVidName, shapeType, currCircleName, circleCordList[0], circleCordList[1], euclidPxDistance] + cv2.imshow('Define shape', img) + cv2.setMouseCallback('Define shape', select_new_dot_location) + if (insertStatus == True): + if coordChange[0] == 1: + cv2.circle(img, (circleCordList[2], circleCordList[3]), DrawScale, (144, 0, 255), -1) + cv2.circle(img, (newCordList[-2], newCordList[-1]), DrawScale, (144, 0, 255), -1) + cv2.circle(img, (circleCordList[0], circleCordList[1]), euclidPxDistance, (144, 0, 255), DrawScale) + circleCordList = [newCordList[-2], newCordList[-1], circleCordList[2], circleCordList[3]] + circleCordAppend = [CurrVidName, shapeType, currCircleName, circleCordList[0], circleCordList[1],euclidPxDistance] + centerCordStatus = True + moveStatus = False + insertStatus = False + changeLoop = True + if coordChange[0] == 2: + cv2.circle(img, (circleCordList[0], circleCordList[1]), DrawScale, (144, 0, 255), -1) + cv2.circle(img, (newCordList[-2], newCordList[-1]), DrawScale, (144, 0, 255), -1) + euclidPxDistance = int((np.sqrt((circleCordList[1] - newCordList[-1]) ** 2 + (circleCordList[0] - newCordList[-2]) ** 2))) + cv2.circle(img, (circleCordList[0], circleCordList[1]), euclidPxDistance, (144, 0, 255), DrawScale) + circleCordList = [circleCordList[0], circleCordList[1], newCordList[-2], newCordList[-1]] + circleCordAppend = [CurrVidName, shapeType, currCircleName, circleCordList[0], circleCordList[1], euclidPxDistance] + centerCordStatus = True + moveStatus = False + insertStatus = False + changeLoop = True + cv2.imshow('Define shape', img) + img = overlay.copy() + k = cv2.waitKey(20) & 0xFF + if k == 27: + circleDf = circleDf.append(pd.Series(dict(zip(circleDf.columns, circleCordAppend))), ignore_index=True) + cv2.destroyWindow('Define shape') + break + + ##### POLYGONS #### + for index, row in pol2draw.iterrows(): + currPolygonName = row['Name'] + shapeType = 'polygon' + im = np.zeros((550, 1000, 3)) + cv2.putText(im, str(CurrVidName), (10, 20), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 255), 2) + cv2.putText(im, 'Draw polygon: ' + str(currPolygonName), (10, 60), cv2.FONT_HERSHEY_SIMPLEX, 0.7 + 0.2, (0, 255, 255), 2) + cv2.putText(im, 'Instructions', (10, 110), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2) + cv2.putText(im, str('Double left click at at least 3 outer bounds of the polygon'), (10, 160), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2) + cv2.putText(im, str('Press ESC start or to continue'), (10, 210), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2) + while (1): + cv2.imshow('Instructions', im) + k = cv2.waitKey(0) + if k==27: + break + overlay = img.copy() + polyGonListOfLists = [] + polygonVertList = [] + cv2.namedWindow('Define shape', cv2.WINDOW_NORMAL) + while (1): + cv2.setMouseCallback('Define shape', draw_polygon_vertices) + cv2.imshow('Define shape', overlay) + k = cv2.waitKey(0) & 0xFF + if k == 27: + if len(polygonVertList) >= 3: + break + else: + pass + # break + #break + polyGon = Polygon(polygonVertList) + polyX, polyY = polyGon.exterior.coords.xy + for i in range(len(polyX)): + polyGonListOfLists.append([polyX[i], polyY[i]]) + polyGonListtoDf = [CurrVidName, shapeType, currPolygonName, polyGonListOfLists] + polyGonListOfLists = np.array(polyGonListOfLists, np.int32) + polyGonListOfLists = polyGonListOfLists.reshape((-1, 1, 2)) + polyLine = cv2.convexHull(polyGonListOfLists) + cv2.drawContours(overlay, [polyLine.astype(int)], 0, (0, 255, 255), DrawScale) + cv2.imshow('Define shape', overlay) + polygonDf = polygonDf.append(pd.Series(dict(zip(polygonDf.columns, polyGonListtoDf))), ignore_index=True) + img = overlay.copy() + cv2.imshow('Define shape', overlay) + k = cv2.waitKey(0) & 0xFF + if k == 27: # Esc key to stop + cv2.destroyWindow('Define shape') + cv2.destroyWindow('Instructions') + # break + # break + cv2.destroyWindow('Define shape') + cv2.destroyWindow('Instructions') + storePath = os.path.join(outPutPath, 'ROI_definitions.h5') + store = pd.HDFStore(storePath, mode='w') + rec = pd.concat([rectangularDf, inputRect], ignore_index=True, sort=False) + circ = pd.concat([circleDf, inputCirc], ignore_index=True, sort=False) + polyg = pd.concat([polygonDf, inputPoly], ignore_index=True, sort=False) + store['rectangles'] = rec + store['circleDf'] = circ + store['polygons'] = polyg + print('ROI definitions saved in ' + str(storePath)) + print('ROI definitions saved in ' + 'project_folder\logs\measures\ROI_definitions.h5') + store.close() + + delImagePath = os.path.join(videofilesFolder, '0.bmp') + os.remove(delImagePath) + + def updateImage(centroids, toRemoveShapeName, rectangularDf, circleDf, polygonDf): + global recWidth, recHeight, firstLoop + overlay = img.copy() + centroids = centroids.drop_duplicates() + for rectangle in range(len(rectangularDf)): + videoName, recName, topLeftX, topLeftY = (rectangularDf['Video'].iloc[rectangle], rectangularDf['Name'].iloc[rectangle], rectangularDf['topLeftX'].iloc[rectangle],rectangularDf['topLeftY'].iloc[rectangle]) + if recName == toRemoveShapeName: + recWidth, recHeight = (rectangularDf['width'].iloc[rectangle], rectangularDf['height'].iloc[rectangle]) + continue + else: + bottomRightX, bottomRightY = (topLeftX + rectangularDf['width'].iloc[rectangle], topLeftY + rectangularDf['height'].iloc[rectangle]) + cv2.rectangle(overlay, (topLeftX, topLeftY), (bottomRightX, bottomRightY), (255, 0, 0), DrawScale) + centerOfShape = [(topLeftX + bottomRightX) / 2, (topLeftY + bottomRightY) / 2] + cv2.circle(overlay, (int(centerOfShape[0]), int(centerOfShape[1])),DrawScale, (255, 0, 0), -1) + if firstLoop == True: + CentroidList = [CurrVidName, 'rectangle', recName, centerOfShape[0], centerOfShape[1]] + centroids = centroids.append(pd.Series(dict(zip(centroids.columns, CentroidList))), ignore_index=True) + else: + centroids.loc[(centroids['Name'] == recName), 'CenterX'] = centerOfShape[0] + centroids.loc[(centroids['Name'] == recName), 'CenterY'] = centerOfShape[1] + correctionMask = (rectangularDf['Name'] == recName) & (rectangularDf['Video'] == videoName) + rectangularDf['topLeftX'][correctionMask], rectangularDf['topLeftY'][correctionMask] = topLeftX, topLeftY + #recListtoDf = [videoName, "ractangle", recName, recWidth, recHeight, topLeftX, topLeftY] + #rectangularDf = rectangularDf.append(pd.Series(dict(zip(rectangularDf.columns, recListtoDf))), ignore_index=True) + for circle in range(len(circleDf)): + videoName, circleName, centerX, centerY, radius = (circleDf['Video'].iloc[circle], circleDf['Name'].iloc[circle], circleDf['centerX'].iloc[circle], circleDf['centerY'].iloc[circle], circleDf['radius'].iloc[circle]) + if circleName == toRemoveShapeName: + continue + else: + cv2.circle(overlay, (centerX, centerY), radius, (144, 0, 255), DrawScale) + cv2.circle(overlay, (centerX, centerY), DrawScale, (144, 0, 255), -1) + if firstLoop == True: + CentroidList = [CurrVidName, 'circle', circleName, centerX, centerY] + centroids = centroids.append(pd.Series(dict(zip(centroids.columns, CentroidList))), ignore_index=True) + else: + centroids.loc[(centroids['Name'] == circleName), 'CenterX'] = centerX + centroids.loc[(centroids['Name'] == circleName), 'CenterY'] = centerY + correctionMask = (circleDf['Name'] == circleName) & (circleDf['Video'] == videoName) + circleDf['centerX'][correctionMask], circleDf['centerY'][correctionMask] = centerX, centerY + #for polygon in range(len(polygonDf)): + for index, row in polygonDf.iterrows(): + videoName, polyName, inputVertices = (row['Video'], row['Name'], row['vertices']) + if polyName == toRemoveShapeName: + continue + else: + sumofX, sumofY = (int(sum([item[0] for item in inputVertices])), int(sum([item[1] for item in inputVertices]))) + PolyCentroidX, PolyCentroidY = (int(sumofX / len(inputVertices)), int(sumofY / len(inputVertices))) + cv2.circle(overlay, (PolyCentroidX, PolyCentroidY), DrawScale, (0,255,255), -1) + vertices = np.array(inputVertices, np.int32) + cv2.polylines(overlay, [vertices], True, (0, 255, 255), thickness=DrawScale) + if firstLoop == True: + CentroidList = [CurrVidName, 'polygon', polyName, PolyCentroidX, PolyCentroidY] + centroids = centroids.append(pd.Series(dict(zip(centroids.columns, CentroidList))), ignore_index=True) + else: + centroids.loc[(centroids['Name'] == polyName), 'CenterX'] = PolyCentroidX + centroids.loc[(centroids['Name'] == polyName), 'CenterY'] = PolyCentroidY + polygonDf = polygonDf.drop(polygonDf[(polygonDf['Video'] == videoName) & (polygonDf['Name'] == polyName)].index) + polyGonListtoDf = [videoName, 'polygon', polyName, inputVertices] + polygonDf = polygonDf.append(pd.Series(dict(zip(polygonDf.columns, polyGonListtoDf))), ignore_index=True) + firstLoop = False + cv2.imshow('Define shape', overlay) + return centroids + + if (ROIdefExist is True) and (vidROIDefs is True): + firstLoop = True + cap = cv2.VideoCapture(currVid) + cap.set(1, 0) + ret, frame = cap.read() + fileName = str(0) + str('.bmp') + filePath = os.path.join(videofilesFolder, fileName) + cv2.imwrite(filePath, frame) + img = cv2.imread(filePath) + overlay = img.copy() + CurrVidName = os.path.splitext(os.path.basename(currVid))[0] + centroids = pd.DataFrame(columns=['Video', "Shape", "Name", "CenterX", "CenterY"]) + toRemoveShapeName = '' + removeStatus = True + ix, iy = -1, -1 + im = np.zeros((400, 1000, 3)) + cv2.putText(im, 'Move shapes for ' + str(CurrVidName), (10, 20), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 255), 2) + cv2.putText(im, 'Instructions', (10, 60), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2) + cv2.putText(im, str('Double left click on the centroid of the shape you wish to move'), (10, 110), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2) + cv2.putText(im, str('Then double click in the new centroid location'), (10, 160), cv2.FONT_HERSHEY_SIMPLEX,0.7, (255, 255, 255), 2) + cv2.putText(im, str('Press ESC to start and when finished'), (10, 210), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2) + while (1): + cv2.imshow('Instructions', im) + k = cv2.waitKey(0) + if k == 27: # Esc key to stop + break + while (1): + cv2.namedWindow('Define shape', cv2.WINDOW_NORMAL) + centroids = updateImage(centroids, toRemoveShapeName, rectangularDf, circleDf, polygonDf) + if removeStatus == True: + cv2.setMouseCallback('Define shape', select_shape_to_change) + if removeStatus == False: + cv2.setMouseCallback('Define shape', select_new_shape_centroid_loc) + k = cv2.waitKey(50) & 0xFF + if k == 27: + cv2.destroyWindow('Define shape') + cv2.destroyWindow('Instructions') + break + cv2.destroyWindow('Define shape') + cv2.destroyWindow('Instructions') + store = pd.HDFStore(storePath, mode='w') + rec = pd.concat([rectangularDf, inputRect], ignore_index=True, sort=False) + circ = pd.concat([circleDf, inputCirc], ignore_index=True, sort=False) + polyg = pd.concat([polygonDf, inputPoly], ignore_index=True, sort=False) + store['rectangles'] = rec + store['circleDf'] = circ + store['polygons'] = polyg + print('ROI definitions saved in ' + 'project_folder\logs\measures\ROI_definitions.h5') + store.close() + + delImagePath = os.path.join(videofilesFolder, '0.bmp') + os.remove(delImagePath) + + + + + diff --git a/simba/ROI_multiply.py b/simba/ROI_multiply.py index c0275fab1..db10171a3 100644 --- a/simba/ROI_multiply.py +++ b/simba/ROI_multiply.py @@ -1,47 +1,47 @@ -import glob -import pandas as pd -from configparser import ConfigParser -import os - -def multiplyFreeHand(inifile, currVid): - CurrVidName = os.path.basename(currVid).replace('.mp4', '') - config = ConfigParser() - configFile = str(inifile) - config.read(configFile) - projectPath = config.get('General settings', 'project_path') - videoPath = os.path.join(projectPath, 'videos') - ROIcoordinatesPath = os.path.join(projectPath, 'logs', 'measures', 'ROI_definitions.h5') - try: - rectanglesInfo = pd.read_hdf(ROIcoordinatesPath, key='rectangles') - circleInfo = pd.read_hdf(ROIcoordinatesPath, key='circleDf') - polygonInfo = pd.read_hdf(ROIcoordinatesPath, key='polygons') - rectangularDf = rectanglesInfo.loc[rectanglesInfo['Video'] == str(CurrVidName)] - circleDf = circleInfo.loc[circleInfo['Video'] == str(CurrVidName)] - polygonDf = polygonInfo.loc[polygonInfo['Video'] == str(CurrVidName)] - ROIdefExist = True - except FileNotFoundError: - ROIdefExist = False - print('Cannot apply to all: no ROI definitions exists') - - if ROIdefExist is True: - if (len(rectangularDf) == 0 and len(circleDf) == 0 and len(polygonDf) == 0): - print('Cannot apply ROIs to all: no records exist for ' + str(CurrVidName)) - else: - videofilesFound = glob.glob(videoPath + '/*.mp4') - duplicatedRec, duplicatedCirc, duplicatedPoly = (rectangularDf.copy(), circleDf.copy(), polygonDf.copy()) - for vids in videofilesFound: - currVidName = os.path.basename(vids).replace('.mp4', '') - duplicatedRec['Video'], duplicatedCirc['Video'], duplicatedPoly['Video'] = (currVidName, currVidName, currVidName) - rectangularDf = rectangularDf.append(duplicatedRec, ignore_index=True) - circleDf = circleDf.append(duplicatedCirc, ignore_index=True) - polygonDf = polygonDf.append(duplicatedPoly, ignore_index=True) - rectangularDf = rectangularDf.drop_duplicates(subset=['Video', 'Name'], keep="first") - circleDf = circleDf.drop_duplicates(subset=['Video', 'Name'], keep="first") - polygonDf = polygonDf.drop_duplicates(subset=['Video', 'Name'], keep="first") - store = pd.HDFStore(ROIcoordinatesPath, mode='w') - store['rectangles'] = rectangularDf - store['circleDf'] = circleDf - store['polygons'] = polygonDf - store.close() - print('ROI(s) for ' + CurrVidName + ' applied to all videos') - print('Next, click on "draw" to modify ROI location(s) or click on "reset" to remove ROI drawing(s)') +import glob +import pandas as pd +from configparser import ConfigParser +import os + +def multiplyFreeHand(inifile, currVid): + CurrVidName = os.path.splitext(os.path.basename(currVid))[0] + config = ConfigParser() + configFile = str(inifile) + config.read(configFile) + projectPath = config.get('General settings', 'project_path') + videoPath = os.path.join(projectPath, 'videos') + ROIcoordinatesPath = os.path.join(projectPath, 'logs', 'measures', 'ROI_definitions.h5') + try: + rectanglesInfo = pd.read_hdf(ROIcoordinatesPath, key='rectangles') + circleInfo = pd.read_hdf(ROIcoordinatesPath, key='circleDf') + polygonInfo = pd.read_hdf(ROIcoordinatesPath, key='polygons') + rectangularDf = rectanglesInfo.loc[rectanglesInfo['Video'] == str(CurrVidName)] + circleDf = circleInfo.loc[circleInfo['Video'] == str(CurrVidName)] + polygonDf = polygonInfo.loc[polygonInfo['Video'] == str(CurrVidName)] + ROIdefExist = True + except FileNotFoundError: + ROIdefExist = False + print('Cannot apply to all: no ROI definitions exists') + + if ROIdefExist is True: + if (len(rectangularDf) == 0 and len(circleDf) == 0 and len(polygonDf) == 0): + print('Cannot apply ROIs to all: no records exist for ' + str(CurrVidName)) + else: + videofilesFound = glob.glob(videoPath + '/*.mp4') + glob.glob(videoPath + '/*.avi') + duplicatedRec, duplicatedCirc, duplicatedPoly = (rectangularDf.copy(), circleDf.copy(), polygonDf.copy()) + for vids in videofilesFound: + currVidName = os.path.splitext(os.path.basename(vids))[0] + duplicatedRec['Video'], duplicatedCirc['Video'], duplicatedPoly['Video'] = (currVidName, currVidName, currVidName) + rectangularDf = rectangularDf.append(duplicatedRec, ignore_index=True) + circleDf = circleDf.append(duplicatedCirc, ignore_index=True) + polygonDf = polygonDf.append(duplicatedPoly, ignore_index=True) + rectangularDf = rectangularDf.drop_duplicates(subset=['Video', 'Name'], keep="first") + circleDf = circleDf.drop_duplicates(subset=['Video', 'Name'], keep="first") + polygonDf = polygonDf.drop_duplicates(subset=['Video', 'Name'], keep="first") + store = pd.HDFStore(ROIcoordinatesPath, mode='w') + store['rectangles'] = rectangularDf + store['circleDf'] = circleDf + store['polygons'] = polygonDf + store.close() + print('ROI(s) for ' + CurrVidName + ' applied to all videos') + print('Next, click on "draw" to modify ROI location(s) or click on "reset" to remove ROI drawing(s)') diff --git a/simba/ROI_plot.py b/simba/ROI_plot.py index 78b4ba2d0..c4d1ced6e 100644 --- a/simba/ROI_plot.py +++ b/simba/ROI_plot.py @@ -1,190 +1,193 @@ -from configparser import ConfigParser -import os -import pandas as pd -import cv2 -import numpy as np -from shapely.geometry import Point -from shapely import geometry -import glob - -def roiPlot(inifile): - config = ConfigParser() - config.read(inifile) - - ## get dataframe column name - bpcsv = (os.path.join(os.path.dirname(inifile), 'logs', 'measures', 'pose_configs', 'bp_names', - 'project_bp_names.csv')) - bplist = [] - with open(bpcsv) as f: - for row in f: - bplist.append(row) - bplist = list(map(lambda x: x.replace('\n', ''), bplist)) - bpcolname = ['scorer'] - for i in bplist: - bpcolname.append(i + '_x') - bpcolname.append(i + '_y') - bpcolname.append(i + '_p') - noAnimals = config.getint('ROI settings', 'no_of_animals') - animalBodypartList = [] - if noAnimals == 2: - arrayIndex = 2 - bodyPartAnimal_1 = config.get('ROI settings', 'animal_1_bp') - animalBodypartList.append(bodyPartAnimal_1) - bodyPartAnimal_2 = config.get('ROI settings', 'animal_2_bp') - animalBodypartList.append(bodyPartAnimal_2) - trackedBodyPartNames = ['Animal_1', 'Animal_2'] - else: - arrayIndex = 1 - bodyPartAnimal_1 = config.get('ROI settings', 'animal_1_bp') - animalBodypartList.append(bodyPartAnimal_1) - trackedBodyPartNames = ['Animal_1'] - trackedBodyParts = [] - for i in range(len(animalBodypartList)): - bps = [str(animalBodypartList[i]) + '_x', str(animalBodypartList[i]) + '_y'] - trackedBodyParts.append(bps) - vidInfPath = config.get('General settings', 'project_path') - videoDirIn = os.path.join(vidInfPath, 'videos') - logFolderPath = os.path.join(vidInfPath, 'logs') - vidInfPath = os.path.join(logFolderPath, 'video_info.csv') - vidinfDf = pd.read_csv(vidInfPath) - csv_dir = config.get('General settings', 'csv_path') - csv_dir_in = os.path.join(csv_dir, 'outlier_corrected_movement_location') - frames_dir_out = config.get('Frame settings', 'frames_dir_out') - frames_dir_out = os.path.join(frames_dir_out, 'ROI_analysis') - if not os.path.exists(frames_dir_out): - os.makedirs(frames_dir_out) - fileCounter = 0 - ROIcoordinatesPath = os.path.join(logFolderPath, 'measures', 'ROI_definitions.h5') - rectanglesInfo = pd.read_hdf(ROIcoordinatesPath, key='rectangles') - circleInfo = pd.read_hdf(ROIcoordinatesPath, key='circleDf') - polygonInfo = pd.read_hdf(ROIcoordinatesPath, key='polygons') - filesFound = glob.glob(csv_dir_in + '/*.csv') - - - for i in filesFound: - fileCounter +=1 - CurrVidFn = os.path.basename(i) - CurrentVideoName = os.path.basename(i).replace('.csv', '') - currentVideo = os.path.join(videoDirIn, CurrentVideoName + '.mp4') - cap = cv2.VideoCapture(currentVideo) - 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)) - frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) - DrawScale = int(max(width, height) / 100) - textScale = max(width, height) / (max(width, height) * 1.6) - space_scale = 1.1 - fourcc = cv2.VideoWriter_fourcc(*'mp4v') - videoSettings = vidinfDf.loc[vidinfDf['Video'] == str(CurrentVideoName)] - currFps = int(videoSettings['fps']) - noRectangles = len(rectanglesInfo.loc[rectanglesInfo['Video'] == str(CurrentVideoName)]) - noCircles = len(circleInfo.loc[circleInfo['Video'] == str(CurrentVideoName)]) - noPolygons = len(polygonInfo.loc[polygonInfo['Video'] == str(CurrentVideoName)]) - rectangleTimes, rectangleEntries = ([[0] * len(trackedBodyParts) for i in range(noRectangles)] , [[0] * len(trackedBodyParts) for i in range(noRectangles)]) - circleTimes, circleEntries = ([[0] * len(trackedBodyParts) for i in range(noCircles)], [[0] * len(trackedBodyParts) for i in range(noCircles)]) - polygonTime, polyGonEntries = ([[0] * len(trackedBodyParts) for i in range(noPolygons)], [[0] * len(trackedBodyParts) for i in range(noPolygons)]) - currFrameFolderOut = os.path.join(frames_dir_out, CurrentVideoName + '.mp4') - - Rectangles = (rectanglesInfo.loc[rectanglesInfo['Video'] == str(CurrentVideoName)]) - Circles = (circleInfo.loc[circleInfo['Video'] == str(CurrentVideoName)]) - Polygons = (polygonInfo.loc[polygonInfo['Video'] == str(CurrentVideoName)]) - rectangleEntryCheck = [[True] * len(trackedBodyParts) for i in range(noRectangles)] - circleEntryCheck = [[True] * len(trackedBodyParts) for i in range(noCircles)] - polygonEntryCheck = [[True] * len(trackedBodyParts) for i in range(noPolygons)] - currDfPath = os.path.join(csv_dir_in, CurrVidFn) - currDf = pd.read_csv(currDfPath, header=0, names=bpcolname) - currRow = 0 - - writer = cv2.VideoWriter(currFrameFolderOut, fourcc, fps, (width*2, height)) - RectangleColors = [(255, 191, 0), (255, 248, 240), (255,144,30), (230,224,176), (160, 158, 95), (208,224,63), (240, 207,137), (245,147,245), (204,142,0), (229,223,176), (208,216,129)] - CircleColors = [(122, 160, 255), (0, 69, 255), (34,34,178), (0,0,255), (128, 128, 240), (2, 56, 121), (21, 113, 239), (5, 150, 235), (2, 106, 253), (0, 191, 255), (98, 152, 247)] - polygonColor = [(0, 255, 0), (87, 139, 46), (152,241,152), (127,255,0), (47, 107, 85), (91, 154, 91), (70, 234, 199), (20, 255, 57), (135, 171, 41), (192, 240, 208), (131,193, 157)] - while (cap.isOpened()): - ret, img = cap.read() - if ret == True: - addSpacer = 2 - spacingScale = int(min(width, height) / (25 / space_scale)) - borderImage = cv2.copyMakeBorder(img, 0,0,0,int(width), borderType=cv2.BORDER_CONSTANT, value=[0, 0, 0]) - borderImageHeight, borderImageWidth = borderImage.shape[0], borderImage.shape[1] - if noAnimals == 2: - currentPoints = (int(currDf.loc[currDf.index[currRow], trackedBodyParts[0][0]]), int(currDf.loc[currDf.index[currRow], trackedBodyParts[1][0]]), int(currDf.loc[currDf.index[currRow], trackedBodyParts[0][1]]), int(currDf.loc[currDf.index[currRow], trackedBodyParts[1][1]])) - cv2.circle(borderImage, (currentPoints[0], currentPoints[2]), DrawScale, (0, 255, 0), -1) - cv2.circle(borderImage, (currentPoints[1], currentPoints[3]), DrawScale, (0, 140, 255), -1) - if noAnimals == 1: - currentPoints = (int(currDf.loc[currDf.index[currRow], trackedBodyParts[0][0]]), int(currDf.loc[currDf.index[currRow], trackedBodyParts[0][1]])) - cv2.circle(borderImage, (currentPoints[0], currentPoints[1]), DrawScale, (0, 255, 0), -1) - addSpacer += 1 - for rectangle in range(noRectangles): - topLeftX, topLeftY = (Rectangles['topLeftX'].iloc[rectangle], Rectangles['topLeftY'].iloc[rectangle]) - bottomRightX, bottomRightY = (topLeftX + Rectangles['width'].iloc[rectangle], topLeftY + Rectangles['height'].iloc[rectangle]) - rectangleName = Rectangles['Name'].iloc[rectangle] - cv2.rectangle(borderImage, (topLeftX, topLeftY), (bottomRightX, bottomRightY), RectangleColors[rectangle], DrawScale) - for bodyparts in range(len(trackedBodyParts)): - cv2.putText(borderImage, str(rectangleName) + ' ' + str(trackedBodyPartNames[bodyparts]) + ' timer:', ((width + 5), (height - (height + 10) + spacingScale*addSpacer)), cv2.FONT_HERSHEY_TRIPLEX, textScale, RectangleColors[rectangle], 2) - if (((topLeftX-10) <= currentPoints[bodyparts] <= (bottomRightX+10)) and ((topLeftY-10) <= currentPoints[bodyparts+arrayIndex] <= (bottomRightY+10))): - rectangleTimes[rectangle][bodyparts] = round((rectangleTimes[rectangle][bodyparts] + (1 / currFps)), 2) - if rectangleEntryCheck[rectangle][bodyparts] == True: - rectangleEntries[rectangle][bodyparts] += 1 - rectangleEntryCheck[rectangle][bodyparts] = False - else: - rectangleEntryCheck[rectangle][bodyparts] = True - cv2.putText(borderImage, str(rectangleTimes[rectangle][bodyparts]), ((int(borderImageWidth-(borderImageWidth/6))), (height - (height + 10) + spacingScale*addSpacer)), cv2.FONT_HERSHEY_TRIPLEX, textScale, RectangleColors[rectangle], 2) - addSpacer += 1 - cv2.putText(borderImage, str(rectangleName) + ' ' + str(trackedBodyPartNames[bodyparts]) + ' entries:', ((width + 5), (height - (height + 10) + spacingScale*addSpacer)), cv2.FONT_HERSHEY_TRIPLEX, textScale, RectangleColors[rectangle], 2) - cv2.putText(borderImage, str(rectangleEntries[rectangle][bodyparts]), ((int(borderImageWidth-(borderImageWidth/6))), (height - (height + 10) + spacingScale*addSpacer)), cv2.FONT_HERSHEY_TRIPLEX, textScale, RectangleColors[rectangle], 2) - addSpacer += 1 - - for circle in range(noCircles): - circleName, centerX, centerY, radius = (Circles['Name'].iloc[circle], Circles['centerX'].iloc[circle], Circles['centerY'].iloc[circle], Circles['radius'].iloc[circle]) - cv2.circle(borderImage, (centerX, centerY), radius, CircleColors[circle], DrawScale) - for bodyparts in range(len(trackedBodyParts)): - cv2.putText(borderImage, str(circleName) + ' ' +str(trackedBodyPartNames[bodyparts]) + ' timer:', ((width + 5), (height - (height + 10) + spacingScale*addSpacer)), cv2.FONT_HERSHEY_TRIPLEX, textScale, CircleColors[circle], 2) - euclidPxDistance = int(np.sqrt((currentPoints[bodyparts] - centerX) ** 2 + (currentPoints[bodyparts+arrayIndex] - centerY) ** 2)) - if euclidPxDistance <= radius: - circleTimes[circle][bodyparts] = round((circleTimes[circle][bodyparts] + (1 / currFps)),2) - if circleEntryCheck[circle][bodyparts] == True: - circleEntries[circle][bodyparts] += 1 - circleEntryCheck[circle][bodyparts] = False - else: - circleEntryCheck[circle][bodyparts] = True - cv2.putText(borderImage, str(circleTimes[circle][bodyparts]), ((int(borderImageWidth-(borderImageWidth/6))), (height - (height + 10) + spacingScale*addSpacer)), cv2.FONT_HERSHEY_TRIPLEX, textScale, CircleColors[circle], 2) - addSpacer += 1 - cv2.putText(borderImage, str(circleName) + ' ' + str(trackedBodyPartNames[bodyparts]) + ' entries:', ((width + 5), (height - (height + 10) + spacingScale*addSpacer)), cv2.FONT_HERSHEY_TRIPLEX, textScale, CircleColors[circle], 2) - cv2.putText(borderImage, str(circleEntries[circle][bodyparts]), ((int(borderImageWidth-(borderImageWidth/6))), (height - (height + 10) + spacingScale*addSpacer)), cv2.FONT_HERSHEY_TRIPLEX, textScale, CircleColors[circle], 2) - addSpacer += 1 - - for polygon in range(noPolygons): - PolygonName, vertices = (Polygons['Name'].iloc[polygon], Polygons['vertices'].iloc[polygon]) - vertices = np.array(vertices, np.int32) - cv2.polylines(borderImage, [vertices], True, polygonColor[polygon], thickness=DrawScale) - for bodyparts in range(len(trackedBodyParts)): - pointList = [] - cv2.putText(borderImage, str(PolygonName) + ' ' + str(trackedBodyPartNames[bodyparts]) + ' timer:', ((width + 5), (height - (height + 10) + spacingScale * addSpacer)), cv2.FONT_HERSHEY_TRIPLEX, textScale, polygonColor[polygon], 2) - for i in vertices: - point = geometry.Point(i) - pointList.append(point) - polyGon = geometry.Polygon([[p.x, p.y] for p in pointList]) - CurrPoint = Point(int(currentPoints[bodyparts]), int(currentPoints[bodyparts+arrayIndex])) - polyGonStatus = (polyGon.contains(CurrPoint)) - if polyGonStatus == True: - polygonTime[polygon][bodyparts] = round((polygonTime[polygon][bodyparts] + (1 / currFps)), 2) - if polygonEntryCheck[polygon][bodyparts] == True: - polyGonEntries[polygon][bodyparts] += 1 - polygonEntryCheck[polygon][bodyparts] = False - else: - polygonEntryCheck[polygon][bodyparts] = True - cv2.putText(borderImage, str(polygonTime[polygon][bodyparts]), ((int(borderImageWidth-(borderImageWidth/6))), (height - (height + 10) + spacingScale * addSpacer)), cv2.FONT_HERSHEY_TRIPLEX, textScale, polygonColor[polygon], 2) - addSpacer += 1 - cv2.putText(borderImage, str(PolygonName) + ' ' + str(trackedBodyPartNames[bodyparts]) + ' entries:', ((width + 5), (height - (height + 10) + spacingScale*addSpacer)), cv2.FONT_HERSHEY_TRIPLEX, textScale, polygonColor[polygon], 2) - cv2.putText(borderImage, str(polyGonEntries[polygon][bodyparts]), ((int(borderImageWidth-(borderImageWidth/6))), (height - (height + 10) + spacingScale*addSpacer)), cv2.FONT_HERSHEY_TRIPLEX, textScale, polygonColor[polygon], 2) - addSpacer += 1 - #borderImage = cv2.cvtColor(borderImage, cv2.COLOR_RGB2BGR) - borderImage = np.uint8(borderImage) - writer.write(borderImage) - currRow += 1 - print('Frame: ' + str(currRow) + '/' + str(frames) + '. Video ' + str(fileCounter) + '/' + str(len(filesFound))) - if img is None: - print('Video ' + str(CurrentVideoName) + ' saved.') - cap.release() - break +from configparser import ConfigParser +import os +import pandas as pd +import cv2 +import numpy as np +from shapely.geometry import Point +from shapely import geometry +import glob + +def roiPlot(inifile): + config = ConfigParser() + config.read(inifile) + + ## get dataframe column name + bpcsv = (os.path.join(os.path.dirname(inifile), 'logs', 'measures', 'pose_configs', 'bp_names', + 'project_bp_names.csv')) + bplist = [] + with open(bpcsv) as f: + for row in f: + bplist.append(row) + bplist = list(map(lambda x: x.replace('\n', ''), bplist)) + bpcolname = ['scorer'] + for i in bplist: + bpcolname.append(i + '_x') + bpcolname.append(i + '_y') + bpcolname.append(i + '_p') + noAnimals = config.getint('ROI settings', 'no_of_animals') + animalBodypartList = [] + if noAnimals == 2: + arrayIndex = 2 + bodyPartAnimal_1 = config.get('ROI settings', 'animal_1_bp') + animalBodypartList.append(bodyPartAnimal_1) + bodyPartAnimal_2 = config.get('ROI settings', 'animal_2_bp') + animalBodypartList.append(bodyPartAnimal_2) + trackedBodyPartNames = ['Animal_1', 'Animal_2'] + else: + arrayIndex = 1 + bodyPartAnimal_1 = config.get('ROI settings', 'animal_1_bp') + animalBodypartList.append(bodyPartAnimal_1) + trackedBodyPartNames = ['Animal_1'] + trackedBodyParts = [] + for i in range(len(animalBodypartList)): + bps = [str(animalBodypartList[i]) + '_x', str(animalBodypartList[i]) + '_y'] + trackedBodyParts.append(bps) + vidInfPath = config.get('General settings', 'project_path') + videoDirIn = os.path.join(vidInfPath, 'videos') + logFolderPath = os.path.join(vidInfPath, 'logs') + vidInfPath = os.path.join(logFolderPath, 'video_info.csv') + vidinfDf = pd.read_csv(vidInfPath) + csv_dir = config.get('General settings', 'csv_path') + csv_dir_in = os.path.join(csv_dir, 'outlier_corrected_movement_location') + frames_dir_out = config.get('Frame settings', 'frames_dir_out') + frames_dir_out = os.path.join(frames_dir_out, 'ROI_analysis') + if not os.path.exists(frames_dir_out): + os.makedirs(frames_dir_out) + fileCounter = 0 + ROIcoordinatesPath = os.path.join(logFolderPath, 'measures', 'ROI_definitions.h5') + rectanglesInfo = pd.read_hdf(ROIcoordinatesPath, key='rectangles') + circleInfo = pd.read_hdf(ROIcoordinatesPath, key='circleDf') + polygonInfo = pd.read_hdf(ROIcoordinatesPath, key='polygons') + filesFound = glob.glob(csv_dir_in + '/*.csv') + + + for i in filesFound: + fileCounter +=1 + CurrVidFn = os.path.basename(i) + CurrentVideoName = os.path.basename(i).replace('.csv', '') + if os.path.isfile(os.path.join(videoDirIn, CurrentVideoName + '.mp4')): + currentVideo = os.path.join(videoDirIn, CurrentVideoName + '.mp4') + else: + currentVideo = os.path.join(videoDirIn, CurrentVideoName + '.avi') + cap = cv2.VideoCapture(currentVideo) + 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)) + frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) + DrawScale = int(max(width, height) / 100) + textScale = max(width, height) / (max(width, height) * 1.6) + space_scale = 1.1 + fourcc = cv2.VideoWriter_fourcc(*'mp4v') + videoSettings = vidinfDf.loc[vidinfDf['Video'] == str(CurrentVideoName)] + currFps = int(videoSettings['fps']) + noRectangles = len(rectanglesInfo.loc[rectanglesInfo['Video'] == str(CurrentVideoName)]) + noCircles = len(circleInfo.loc[circleInfo['Video'] == str(CurrentVideoName)]) + noPolygons = len(polygonInfo.loc[polygonInfo['Video'] == str(CurrentVideoName)]) + rectangleTimes, rectangleEntries = ([[0] * len(trackedBodyParts) for i in range(noRectangles)] , [[0] * len(trackedBodyParts) for i in range(noRectangles)]) + circleTimes, circleEntries = ([[0] * len(trackedBodyParts) for i in range(noCircles)], [[0] * len(trackedBodyParts) for i in range(noCircles)]) + polygonTime, polyGonEntries = ([[0] * len(trackedBodyParts) for i in range(noPolygons)], [[0] * len(trackedBodyParts) for i in range(noPolygons)]) + currFrameFolderOut = os.path.join(frames_dir_out, CurrentVideoName + '.mp4') + + Rectangles = (rectanglesInfo.loc[rectanglesInfo['Video'] == str(CurrentVideoName)]) + Circles = (circleInfo.loc[circleInfo['Video'] == str(CurrentVideoName)]) + Polygons = (polygonInfo.loc[polygonInfo['Video'] == str(CurrentVideoName)]) + rectangleEntryCheck = [[True] * len(trackedBodyParts) for i in range(noRectangles)] + circleEntryCheck = [[True] * len(trackedBodyParts) for i in range(noCircles)] + polygonEntryCheck = [[True] * len(trackedBodyParts) for i in range(noPolygons)] + currDfPath = os.path.join(csv_dir_in, CurrVidFn) + currDf = pd.read_csv(currDfPath, header=0, names=bpcolname) + currRow = 0 + + writer = cv2.VideoWriter(currFrameFolderOut, fourcc, fps, (width*2, height)) + RectangleColors = [(255, 191, 0), (255, 248, 240), (255,144,30), (230,224,176), (160, 158, 95), (208,224,63), (240, 207,137), (245,147,245), (204,142,0), (229,223,176), (208,216,129)] + CircleColors = [(122, 160, 255), (0, 69, 255), (34,34,178), (0,0,255), (128, 128, 240), (2, 56, 121), (21, 113, 239), (5, 150, 235), (2, 106, 253), (0, 191, 255), (98, 152, 247)] + polygonColor = [(0, 255, 0), (87, 139, 46), (152,241,152), (127,255,0), (47, 107, 85), (91, 154, 91), (70, 234, 199), (20, 255, 57), (135, 171, 41), (192, 240, 208), (131,193, 157)] + while (cap.isOpened()): + ret, img = cap.read() + if ret == True: + addSpacer = 2 + spacingScale = int(min(width, height) / (25 / space_scale)) + borderImage = cv2.copyMakeBorder(img, 0,0,0,int(width), borderType=cv2.BORDER_CONSTANT, value=[0, 0, 0]) + borderImageHeight, borderImageWidth = borderImage.shape[0], borderImage.shape[1] + if noAnimals == 2: + currentPoints = (int(currDf.loc[currDf.index[currRow], trackedBodyParts[0][0]]), int(currDf.loc[currDf.index[currRow], trackedBodyParts[1][0]]), int(currDf.loc[currDf.index[currRow], trackedBodyParts[0][1]]), int(currDf.loc[currDf.index[currRow], trackedBodyParts[1][1]])) + cv2.circle(borderImage, (currentPoints[0], currentPoints[2]), DrawScale, (0, 255, 0), -1) + cv2.circle(borderImage, (currentPoints[1], currentPoints[3]), DrawScale, (0, 140, 255), -1) + if noAnimals == 1: + currentPoints = (int(currDf.loc[currDf.index[currRow], trackedBodyParts[0][0]]), int(currDf.loc[currDf.index[currRow], trackedBodyParts[0][1]])) + cv2.circle(borderImage, (currentPoints[0], currentPoints[1]), DrawScale, (0, 255, 0), -1) + addSpacer += 1 + for rectangle in range(noRectangles): + topLeftX, topLeftY = (Rectangles['topLeftX'].iloc[rectangle], Rectangles['topLeftY'].iloc[rectangle]) + bottomRightX, bottomRightY = (topLeftX + Rectangles['width'].iloc[rectangle], topLeftY + Rectangles['height'].iloc[rectangle]) + rectangleName = Rectangles['Name'].iloc[rectangle] + cv2.rectangle(borderImage, (topLeftX, topLeftY), (bottomRightX, bottomRightY), RectangleColors[rectangle], DrawScale) + for bodyparts in range(len(trackedBodyParts)): + cv2.putText(borderImage, str(rectangleName) + ' ' + str(trackedBodyPartNames[bodyparts]) + ' timer:', ((width + 5), (height - (height + 10) + spacingScale*addSpacer)), cv2.FONT_HERSHEY_TRIPLEX, textScale, RectangleColors[rectangle], 2) + if (((topLeftX-10) <= currentPoints[bodyparts] <= (bottomRightX+10)) and ((topLeftY-10) <= currentPoints[bodyparts+arrayIndex] <= (bottomRightY+10))): + rectangleTimes[rectangle][bodyparts] = round((rectangleTimes[rectangle][bodyparts] + (1 / currFps)), 2) + if rectangleEntryCheck[rectangle][bodyparts] == True: + rectangleEntries[rectangle][bodyparts] += 1 + rectangleEntryCheck[rectangle][bodyparts] = False + else: + rectangleEntryCheck[rectangle][bodyparts] = True + cv2.putText(borderImage, str(rectangleTimes[rectangle][bodyparts]), ((int(borderImageWidth-(borderImageWidth/6))), (height - (height + 10) + spacingScale*addSpacer)), cv2.FONT_HERSHEY_TRIPLEX, textScale, RectangleColors[rectangle], 2) + addSpacer += 1 + cv2.putText(borderImage, str(rectangleName) + ' ' + str(trackedBodyPartNames[bodyparts]) + ' entries:', ((width + 5), (height - (height + 10) + spacingScale*addSpacer)), cv2.FONT_HERSHEY_TRIPLEX, textScale, RectangleColors[rectangle], 2) + cv2.putText(borderImage, str(rectangleEntries[rectangle][bodyparts]), ((int(borderImageWidth-(borderImageWidth/6))), (height - (height + 10) + spacingScale*addSpacer)), cv2.FONT_HERSHEY_TRIPLEX, textScale, RectangleColors[rectangle], 2) + addSpacer += 1 + + for circle in range(noCircles): + circleName, centerX, centerY, radius = (Circles['Name'].iloc[circle], Circles['centerX'].iloc[circle], Circles['centerY'].iloc[circle], Circles['radius'].iloc[circle]) + cv2.circle(borderImage, (centerX, centerY), radius, CircleColors[circle], DrawScale) + for bodyparts in range(len(trackedBodyParts)): + cv2.putText(borderImage, str(circleName) + ' ' +str(trackedBodyPartNames[bodyparts]) + ' timer:', ((width + 5), (height - (height + 10) + spacingScale*addSpacer)), cv2.FONT_HERSHEY_TRIPLEX, textScale, CircleColors[circle], 2) + euclidPxDistance = int(np.sqrt((currentPoints[bodyparts] - centerX) ** 2 + (currentPoints[bodyparts+arrayIndex] - centerY) ** 2)) + if euclidPxDistance <= radius: + circleTimes[circle][bodyparts] = round((circleTimes[circle][bodyparts] + (1 / currFps)),2) + if circleEntryCheck[circle][bodyparts] == True: + circleEntries[circle][bodyparts] += 1 + circleEntryCheck[circle][bodyparts] = False + else: + circleEntryCheck[circle][bodyparts] = True + cv2.putText(borderImage, str(circleTimes[circle][bodyparts]), ((int(borderImageWidth-(borderImageWidth/6))), (height - (height + 10) + spacingScale*addSpacer)), cv2.FONT_HERSHEY_TRIPLEX, textScale, CircleColors[circle], 2) + addSpacer += 1 + cv2.putText(borderImage, str(circleName) + ' ' + str(trackedBodyPartNames[bodyparts]) + ' entries:', ((width + 5), (height - (height + 10) + spacingScale*addSpacer)), cv2.FONT_HERSHEY_TRIPLEX, textScale, CircleColors[circle], 2) + cv2.putText(borderImage, str(circleEntries[circle][bodyparts]), ((int(borderImageWidth-(borderImageWidth/6))), (height - (height + 10) + spacingScale*addSpacer)), cv2.FONT_HERSHEY_TRIPLEX, textScale, CircleColors[circle], 2) + addSpacer += 1 + + for polygon in range(noPolygons): + PolygonName, vertices = (Polygons['Name'].iloc[polygon], Polygons['vertices'].iloc[polygon]) + vertices = np.array(vertices, np.int32) + cv2.polylines(borderImage, [vertices], True, polygonColor[polygon], thickness=DrawScale) + for bodyparts in range(len(trackedBodyParts)): + pointList = [] + cv2.putText(borderImage, str(PolygonName) + ' ' + str(trackedBodyPartNames[bodyparts]) + ' timer:', ((width + 5), (height - (height + 10) + spacingScale * addSpacer)), cv2.FONT_HERSHEY_TRIPLEX, textScale, polygonColor[polygon], 2) + for i in vertices: + point = geometry.Point(i) + pointList.append(point) + polyGon = geometry.Polygon([[p.x, p.y] for p in pointList]) + CurrPoint = Point(int(currentPoints[bodyparts]), int(currentPoints[bodyparts+arrayIndex])) + polyGonStatus = (polyGon.contains(CurrPoint)) + if polyGonStatus == True: + polygonTime[polygon][bodyparts] = round((polygonTime[polygon][bodyparts] + (1 / currFps)), 2) + if polygonEntryCheck[polygon][bodyparts] == True: + polyGonEntries[polygon][bodyparts] += 1 + polygonEntryCheck[polygon][bodyparts] = False + else: + polygonEntryCheck[polygon][bodyparts] = True + cv2.putText(borderImage, str(polygonTime[polygon][bodyparts]), ((int(borderImageWidth-(borderImageWidth/6))), (height - (height + 10) + spacingScale * addSpacer)), cv2.FONT_HERSHEY_TRIPLEX, textScale, polygonColor[polygon], 2) + addSpacer += 1 + cv2.putText(borderImage, str(PolygonName) + ' ' + str(trackedBodyPartNames[bodyparts]) + ' entries:', ((width + 5), (height - (height + 10) + spacingScale*addSpacer)), cv2.FONT_HERSHEY_TRIPLEX, textScale, polygonColor[polygon], 2) + cv2.putText(borderImage, str(polyGonEntries[polygon][bodyparts]), ((int(borderImageWidth-(borderImageWidth/6))), (height - (height + 10) + spacingScale*addSpacer)), cv2.FONT_HERSHEY_TRIPLEX, textScale, polygonColor[polygon], 2) + addSpacer += 1 + #borderImage = cv2.cvtColor(borderImage, cv2.COLOR_RGB2BGR) + borderImage = np.uint8(borderImage) + writer.write(borderImage) + currRow += 1 + print('Frame: ' + str(currRow) + '/' + str(frames) + '. Video ' + str(fileCounter) + '/' + str(len(filesFound))) + if img is None: + print('Video ' + str(CurrentVideoName) + ' saved.') + cap.release() + break print('All ROI videos generated in "project_folder/frames/ROI"') \ No newline at end of file