Skip to content
Snippets Groups Projects
Commit 34aab606 authored by Leonardo de Lima Gaspar's avatar Leonardo de Lima Gaspar
Browse files

Restructured for python utilities package, and made standalone utility to...

Restructured for python utilities package, and made standalone utility to generate labelled dataset that can easily be fed into keras later.
parent 10445fd2
No related branches found
No related tags found
No related merge requests found
Showing
with 192 additions and 13 deletions
build/
src\openCV\CMakeLists.txt
*\.venv
dataset/
sourceVideos/
\ No newline at end of file
......@@ -20,7 +20,8 @@ ofstream createCSV(filesystem::path videoFilePath);
// and returns true for when the ratio of the sum of those changes is sufficiently large.
bool detectChange(Mat firstFrame, Mat secFrame);
double percentChangeThreshold = 0.00001;
double percentChangeThreshold = 0.001;
double avg = 0;
int main(int argc, char** argv) {
if (argc != 2) {
......@@ -41,7 +42,7 @@ int main(int argc, char** argv) {
VideoCapture decoder(videoPath.string());
auto start = chrono::steady_clock::now();
int detectionsPerSec = 2;
int detectionsPerSec = 3;
// Amount of extra time each detection interval will be padded with.
double paddingTime_s = 1;
......@@ -52,7 +53,9 @@ int main(int argc, char** argv) {
maxPixelStability maximum allowed credit for a pixel in history
isParallel determines if we're parallelizing the algorithm
*/
Ptr<BackgroundSubtractor> p_bgSub = bgsegm::createBackgroundSubtractorCNT(detectionsPerSec, true, 4*detectionsPerSec, true);
//Ptr<BackgroundSubtractor> p_bgSub = bgsegm::createBackgroundSubtractorCNT(detectionsPerSec, true, 4*detectionsPerSec, true);
Ptr<BackgroundSubtractor> p_bgSub = bgsegm::createBackgroundSubtractorGSOC( 0,20,0.003f,0.01f,32,0.01f,0.0022f,0.1f,0.1f,0.0004f,0.0008f );
// Pre-allocation of variables
vector<bool> motionVec;
......@@ -66,11 +69,14 @@ int main(int argc, char** argv) {
Mat binaryNextFrame;
Mat medianBlurFrame;
Mat medianBlurNextFrame;
int blurRadius = 9;
int blurRadius = 5;
int32_t height = decoder.get(CAP_PROP_FRAME_HEIGHT);
int32_t width = decoder.get(CAP_PROP_FRAME_WIDTH);
int32_t newHeight = height/2;
int32_t newWidth = width/2;
bool gotFrame, gotNextFrame;
while (gotFrame = decoder.read(frame)) {
// Skips some amount of "real" frames to reach desired "simulated fps".
......@@ -82,6 +88,9 @@ int main(int argc, char** argv) {
// Applies bg segmentation, median filter to reduce noise, and pushes the change detection result to output vector.
// The frame count might be inaccurate at the moment, such that real frame 24 at time 1s, might be declared as being at time 0.9s. Needs testing.
if (gotFrame && gotNextFrame) {
resize(frame, frame, Size(newWidth, newHeight), 0, 0, INTER_CUBIC);
resize(nextFrame, nextFrame, Size(newWidth, newHeight), 0, 0, INTER_CUBIC);
p_bgSub->apply(frame, binaryFrame, -1);
p_bgSub->apply(nextFrame, binaryNextFrame, -1);
......@@ -94,11 +103,13 @@ int main(int argc, char** argv) {
}
decoder.release();
double test = avg / (double)simFrameTime;
cout << test << "\n";
// Detection interval padding logic; essentially applies 1D dilation (morphological operation).
int framesPaddedEachSide = ceil((paddingTime_s/2)*detectionsPerSec + 0.5);
vector<bool> dilated = motionVec;
for(int i=0; i<motionVec.size(); i++) {
/*for(int i=0; i<motionVec.size(); i++) {
if (motionVec.at(i) == 1) {
for(int k = -framesPaddedEachSide; k <= framesPaddedEachSide; k++) {
int index = i+k;
......@@ -106,7 +117,7 @@ int main(int argc, char** argv) {
dilated.at(index) = 1;
}
}
}
}*/
// Timestamp generator logic; converts simulated frame index to real time in input file. As mentioned above, the math might be inaccurate.
double timePerSimFrame_s = 1/(double)detectionsPerSec;
......@@ -159,5 +170,7 @@ bool detectChange(Mat firstFrame, Mat secFrame) {
sum += firstFrameArr[pos] | secFrameArr[pos];
}
}
return 4*sum/(firstFrame.rows*firstFrame.cols) > percentChangeThreshold;
double ratio = (double)sum/(255*firstFrame.rows*firstFrame.cols);
avg += ratio;
return ratio > percentChangeThreshold;
}
\ No newline at end of file
......@@ -14,7 +14,7 @@ def main(inputVideo):
curDir = os.getcwd()
# Relative path to input folder from the current working directory (often the root of the repo).
repoRootToBinary = "build\\Release"
repoRootToBinary = ""
pathToBinary = os.path.join(curDir, repoRootToBinary)
os.chdir(pathToBinary)
......@@ -27,7 +27,11 @@ def main(inputVideo):
print("No input folder found. Creating it now. Place input video files in that folder.")
return
print("Processing file {file}".format(file=inputVideo))
os.system("opencvtest.exe {input}".format(input="input/{file}".format(file=inputVideo)))
# Classical algorithm, C++ binary
#os.system("opencvtest.exe {input}".format(input="input/{file}".format(file=inputVideo)))
prefix, ext = os.path.splitext(inputVideo)
print("\nVideo processed and outputted to {csv}.".format(csv=prefix+".csv"))
......
......@@ -5,7 +5,7 @@ import logging
import sys
import ffmpeg
import subprocess
import Jaccard
import Jaccard from utilities
# Logger for logging purposes (seeing which file is currently being processed)
logFormat = "%(levelname)s %(asctime)s - %(message)s"
......
No preview for this file type
36,47
192,199
536,544
604,616
735,744
873,887
1141,1169
1235,1244
1296,1305
1346,1354
1453,1459
1527,1532
44,51
78,186
191,202
207,282
284,294
303,310
318,337
337,345
346,357
364,373
380,388
392,410
410,429
430,437
439,457
472,483
493,534
550,562
565,568
570,576
580,625
636,641
650,681
683,703
720,753
758,766
825,836
784,884
890,927
938,954
957,978
989,1023
1042,1089
1098,1114
1121,1125
1133,1144
1145,1148
1150,1156
1160,1475
1482,1685
1687,1740
0,918
929,934
986,995
997,1003
1048,1056
1056,1740
29,34
34,86
109,117
126,132
133,151
152,448
448,542
574,585
596,600
612,621
641,673
698,727
773,794
903,908
947,1047
1142,1160
1229,1251
1295,1337
1402,1416
1420,1451
1453,1469
1469,1498
1513,1543
1629,1666
1723,1740
import cv2
import csv
import os
import numpy as np
import sys
from pathlib import Path
setFPS = 2
resizeWidth = 480
resizeHeight = 270
groundsPath = "src/python/groundTruth/"
### Generates a dataset of labelled images from one video (soon a whole folder) by comparing to ground truth.
### Takes about 5 minutes for a 30 minute input.
def generateDatasetFromFrames(inputVideoPath, desiredFPS):
decoder = cv2.VideoCapture(inputVideoPath)
inputVideo = Path(inputVideoPath).name
sourceNoExt = os.path.splitext(inputVideo)[0]
groundTruthName = "groundTruth_" + sourceNoExt + ".csv"
# Looks for ground truth csv.
groundFound = False
for file in os.listdir(groundsPath):
if file == groundTruthName:
groundTruthCSV = open(groundsPath+file)
groundFound = True
break
if groundFound == False:
print("No ground truth file found to label from.")
return False
step = int(decoder.get(cv2.CAP_PROP_FPS) / desiredFPS)
try:
# Frame reading loop
while True:
ret, frame = decoder.read()
if not ret:
break
# Frame index is one less because .read() gives index of next frame, not current.
# Also does modulo step to simulate lower FPS.
frameNo = int(decoder.get(cv2.CAP_PROP_POS_FRAMES)-1)
if frameNo % step == 0:
frame = cv2.resize(frame, (resizeWidth, resizeHeight), cv2.INTER_CUBIC)
curTime_s = int(decoder.get(cv2.CAP_PROP_POS_MSEC)/1000)
found = False
truthReader = csv.reader(groundTruthCSV)
for row in truthReader:
# Checks that the time, in seconds, of the current frame, is between an interval in the ground truth
if (int(row[0]) <= curTime_s) and (int(row[1]) >= curTime_s):
cv2.imwrite("dataset/fish/" + "frame{number}{source}.jpg".format(number=frameNo, source=sourceNoExt), frame)
found = True
break
# Resets csv iterator
groundTruthCSV.seek(0)
if found == False:
cv2.imwrite("dataset/noFish/" + "frame{number}{source}.jpg".format(number=frameNo, source=sourceNoExt), frame)
print("Frames saved as labelled images in dataset folder.")
return True
finally:
decoder.release()
groundTruthCSV.close()
def main(video,fps):
print(generateDatasetFromFrames(video,fps))
if __name__ == "__main__":
main("sourceVideos/Myggbukta-[2021-05-21_10-47-06]-408.mp4", setFPS)
\ No newline at end of file
......@@ -22,4 +22,6 @@ def calculateSuccess(observedIntervalsList, trueIntervalsList):
union = cumulativeObs + cumulativeTrue
index = cumulativeIntersection / union
ratioObsToReal = cumulativeObs / cumulativeTrue
print(" Correctness: {:.4f}".format(index) + ", or {:.1f}%".format(index*100))
print(" Observed-to-expected ratio: {:.2f}".format(ratioObsToReal) + " --> {sensitivity}".format(sensitivity=("Too sensitive" if ratioObsToReal>1 else "Not sensitive enough")))
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment