Code MTT
Code MTT
/*
* im_processing.cpp
*
* Created on: Sep 3, 2018
* Author: bilal
*/
#include <stdio.h>
#include <math.h>
#include <memory.h>
#include <vector>
#include "opencv2/opencv.hpp"
#include "opencv2/highgui.hpp"
#include "ImProcessing.hpp"
#include "Tracker.hpp"
bool verbose;
int min_size = 80;
int max_size = 12000;
int min_thresh = 120;
int max_thresh = 245;
int base_thresh = 150;
int j;
double min_error; // Max possible min_error
double error;
//************************************************
// Image Processing on base threshold
//************************************************
Preprocess(frame, frame2, base_thresh);
ExtractObjects(frame2, obj_array);
//************************
// Object Matching
//************************
j = BestMatch(tgt, obj_array);
return tgt_meas;
}
obj_struct ExtractBestObject(Mat& frame, Mat& frame2, vector<obj_struct>&
obj_array,
obj_struct tgt_pred)
{
vector<int> thresh_dist;
thresh_dist.clear();
return ExtractBestObject(frame, frame2, obj_array, tgt_pred,
thresh_dist);
}
m = connectedComponentsWithStats(frame, labels,
stats, centroids);
n = ExtractUsefulLabels(stats, stats2, centroids,
centroids2, min_size, max_size);
if(verbose)
cout << "Total labels: " << m << " "
<< "Useful labels: " << n << endl;
ToObjects(stats2, centroids2, obj_array);
return n;
}
int ExtractObjects(Mat& frame, vector<obj_struct>& obj_array, int thresh)
{
int m, n;
Mat labels, stats, centroids;
Mat stats2, centroids2;
m = connectedComponentsWithStats(frame, labels,
stats, centroids);
n = ExtractUsefulLabels(stats, stats2, centroids,
centroids2, min_size, max_size);
if(verbose)
cout << "Total labels: " << m << " "
<< "Useful labels: " << n << endl;
ToObjects(stats2, centroids2, obj_array, thresh);
return n;
}
return obj;
}
Rect r;
r.x = obj.x - SWELL;
r.y = obj.y - SWELL;
r.width = obj.width + 2*SWELL;
r.height = obj.height + 2*SWELL;
int thresh = obj.thresh;
Rect boundary;
boundary.x = 0;
boundary.y = 0;
boundary.width = frame.cols;
boundary.height = frame.rows;
m = connectedComponentsWithStats(frame_bin, labels,
stats, centroids);
n = ExtractUsefulLabels(stats, stats2, centroids,
centroids2, min_size, max_size);
obj_array.clear();
ToObjects(stats2, centroids2, obj_array, thresh);
for(auto th_dist:thresh_dist){
int th = thresh+th_dist;
if(th > max_thresh || th < min_thresh)
continue;
threshold(roi, frame_bin, th, 255, THRESH_BINARY);
m = connectedComponentsWithStats(frame_bin, labels,
stats, centroids);
n = ExtractUsefulLabels(stats, stats2, centroids,
centroids2, min_size, max_size);
obj.aspect = (double)obj.width/obj.height;
obj.cx = centroids.row(i).at<double>(0);
obj.cy = centroids.row(i).at<double>(1);
obj_array.push_back(obj);
}
return i;
}
int ToObjects(Mat& stats, Mat& centroids, vector<obj_struct>& obj_array, int
thresh)
{
int i;
for(i=0;i<stats.rows;i++){
obj_struct obj;
memset(&obj, 0, sizeof(obj));
obj.x = stats.row(i).at<int>(CC_STAT_LEFT);
obj.y = stats.row(i).at<int>(CC_STAT_TOP);
obj.width = stats.row(i).at<int>(CC_STAT_WIDTH);
obj.height = stats.row(i).at<int>(CC_STAT_HEIGHT);
obj.area = stats.row(i).at<int>(CC_STAT_AREA);
obj.aspect = (double)obj.width/obj.height;
obj.cx = centroids.row(i).at<double>(0);
obj.cy = centroids.row(i).at<double>(1);
obj.thresh = thresh;
obj_array.push_back(obj);
}
return i;
}
out_stats = in_stats.clone();
out_centroids = in_centroids.clone();
for(j=0,i=1;i<in_stats.rows;i++){
area = in_stats.at<int>(i,CC_STAT_AREA);
if(area > min_size && area < max_size){
in_stats.row(i).copyTo(out_stats.row(j));
in_centroids.row(i).copyTo(out_centroids.row(j));
j++;
}
}
out_stats.resize(j);
out_centroids.resize(j);
return j;
}
}
return n;
}
int DrawBBox(Mat& frame, const Scalar& color, obj_struct box)
{
Rect r;
r.x = box.x;
r.y = box.y;
r.width = box.width;
r.height = box.height;
rectangle(frame, r, color);
return 1;
}
}
return n;
}
int PrintObjID(Mat& frame, const Scalar& color, obj_struct box)
{
char s[100];
if(box.miss_num)
sprintf(s, "%03d %02d", box.obj_id, box.miss_num);
else
sprintf(s, "%03d", box.obj_id);
return 1;
}
int PrintObjIDs(Mat& frame, const Scalar& color, vector<obj_struct>& obj_array)
{
int n = obj_array.size();
for(obj_struct tgt: obj_array){
PrintObjID(frame, color, tgt);
}
return n;
}
int VacateFrame(Mat& frame, vector<obj_struct>& obj_array)
{
for(obj_struct obj: obj_array){
Rect r;
r.x = obj.x;
r.y = obj.y;
r.width = obj.width;
r.height = obj.height;
rectangle(frame, r, 0, FILLED);
}
return obj_array.size();
}
// return true if r1 contains r2
bool Contains(Rect r1, Rect r2)
{
int ex2, ey2;
ex2 = r2.x + r2.width - 1;
ey2 = r2.y + r2.height - 1;
if(!r1.contains(Point(r2.x, r2.y)))
return 0;
else if(!r1.contains(Point(r2.x, ey2)))
return 0;
else if(!r1.contains(Point(ex2, r2.y)))
return 0;
else if(!r1.contains(Point(ex2, ey2)))
return 0;
else
return 1;
}
bool Overlap(Rect r1, Rect r2)
{
int ex1, ey1;
int ex2, ey2;
ex1 = r1.x + r1.width - 1;
ey1 = r1.y + r1.height - 1;
ex2 = r2.x + r2.width - 1;
ey2 = r2.y + r2.height - 1;
// If one rectangle is to the left
if(ex1 < r2.x || ex2 < r1.x)
return 0;
// If one rectangle is above
else if(ey1 < r2.y || ey2 < r1.y)
return 0;
else
return 1;
}
bool Overlap(obj_struct obj1, obj_struct obj2)
{
Rect r1, r2;
r1.x = obj1.x;
r1.y = obj1.y;
r1.width = obj1.width;
r1.height = obj1.height;
r2.x = obj2.x;
r2.y = obj2.y;
r2.width = obj2.width;
r2.height = obj2.height;
unsigned int i, j;
double error, Pd, Pd_image;
if(obj_array.empty()){
min_error = 1;
return POOR_MATCH; // Future - some other value
}
j = 0;
min_error = CalcError(tgt, obj_array[0]);
min_image_error = image_error;
for(i=1;i<obj_array.size();i++){
error = CalcError(tgt, obj_array[i]);
if(error < min_error){
min_error = error;
min_image_error = image_error;
j = i;
}
}
Pd = 1-min_error;
Pd_image = 1-min_image_error;
obj.Pd = Pd;
obj.Pd_image = Pd_image;
// Inherited Parameters
obj.obj_id = tgt.obj_id;
obj.state = tgt.state;
obj.pred_cx = tgt.pred_cx;
obj.pred_cy = tgt.pred_cy;
obj.vx = tgt.vx;
obj.vy = tgt.vy;
obj.pred_aspect = tgt.aspect;
obj.pred_area = tgt.area;
obj.pred_thresh = tgt.thresh;
}
return j;
}
int BestMatch(obj_struct& tgt, vector<obj_struct>& obj_array, int th)
{
unsigned int i, j;
double error, Pd, Pd_image;
if(obj_array.empty()){
min_error = 1;
return POOR_MATCH; // Future - some other value
}
j = 0;
min_error = CalcError(tgt, obj_array[0]);
if(tgt.thresh > th)
min_error *= 0.99; // Bias towards higher threshold
min_image_error = image_error;
for(i=1;i<obj_array.size();i++){
error = CalcError(tgt, obj_array[i]);
if(obj_array[i].thresh > th)
error *= 0.99; // Bias towards higher threshold
if(error < min_error){
min_error = error;
min_image_error = image_error;
j = i;
}
}
Pd = 1-min_error;
Pd_image = 1-min_image_error;
obj.Pd = Pd;
obj.Pd_image = Pd_image;
// Inherited Parameters
obj.obj_id = tgt.obj_id;
obj.state = tgt.state;
obj.pred_cx = tgt.pred_cx;
obj.pred_cy = tgt.pred_cy;
obj.vx = tgt.vx;
obj.vy = tgt.vy;
obj.pred_aspect = tgt.aspect;
obj.pred_area = tgt.area;
obj.pred_thresh = tgt.thresh;
}
return j;
}
double MinErrorBestMatch(void)
{
return min_error;
}
// ***********************
// Area error calculation
// ***********************
// ***************************
// Position error calculation
// ***************************
// *************************
// Aspect error calculation
// *************************
// Net Error
e_net = w_pos*pos_error + w_image*image_error;
return e_net;
}
Mat frame2;
vector<obj_struct> objs;
selected = -1;
ExtractObjects(frame2, objs);
imshow(window, frame);
setMouseCallback(window, onMouse, &objs);
while(selected < 0)
waitKey(100);
objs[selected].thresh = thresh;
return objs[selected];
Tracker
/*
* Tracker.cpp
*
* Created on: Sep 1, 2018
* Author: bilal
*/
#include <stdlib.h>
#include <math.h>
#include <memory.h>
#include "opencv2/opencv.hpp"
#include "ImProcessing.hpp"
#include "Tracker.hpp"
int master_obj_count;
extern vector<int> thresh_dist;
extern Mat frame_in, frame_bin;
// Following function operates globally as well as locally
// Local operation
for(auto obj:obj_array_prev){
if(obj.state <=1){ // Initially only global search
obj_array_temp.push_back(obj);
continue;
}
j = SearchObject(frame_gray, obj, th_dist);
if(j<0){ // Object not found -> try globally
if(obj.miss_num < MAX_MISS_NUM){
UpdateTrajectory(obj);
obj_array_temp.push_back(obj);
}
}
else
obj_array_local.push_back(obj);
}
//VacateFrame(frame_bin, obj_array_local);
//imshow("Processed Video", frame_bin);
//waitKey(1000);
obj_array.clear();
ExtractObjects(frame_bin, obj_array, base_thresh);
//DrawBBoxes(frame_in, Scalar(0, 0, 255), obj_array);
//DrawBBoxes(frame_in, Scalar(255, 255, 0), obj_array_local);
//imshow("Video", frame_in);
//waitKey(100);
RemoveOverlappingObjs(obj_array, obj_array_local);
obj_array_prev = obj_array_temp;
CorrelateObjs(obj_array_prev, obj_array);
obj_array.insert(obj_array.begin(),
obj_array_local.begin(), obj_array_local.end());
return obj_array.size();
for(auto obj:obj_array_prev){
j = BestMatch(obj, obj_array);
switch(j){
case OBJ_NO_FREE: // Already matched
// Future implementation// Select better of the two
case POOR_MATCH: // Object not found
if(obj.state <= 1){ // Missed before
initialization
// No action deletes the object
}else if(obj.miss_num < MAX_MISS_NUM){
obj.miss_num++;
UpdateTrajectory(obj);
obj_array_temp.push_back(obj);
//obj_array.insert(obj_array.begin(), obj);
//obj_array.push_back(obj);
//cout << obj.cx << endl;
}
break;
default:
break;
}
i++;
}
obj_array.insert(obj_array.begin(),
obj_array_temp.begin(), obj_array_temp.end());
for(auto& obj:obj_array){
if(!obj.obj_id){ // New Object
obj.obj_id = ++master_obj_count;
obj.state = 0;
}
}
return i;
}
switch(tgt_meas.state){
case 0: // Initialization only
tgt_meas.pred_cx = tgt_meas.cx;
tgt_meas.pred_cy = tgt_meas.cy;
tgt_meas.pred_aspect= tgt_meas.aspect;
tgt_meas.pred_area = tgt_meas.area;
tgt_meas.pred_thresh= tgt_meas.thresh;
tgt_meas.state++;
tgt_est = tgt_meas;
return tgt_meas;
break;
case 1: // Start tracking
K = 1;
K1 = 1;
K2 = 1;
K_thresh = 0;
tgt_meas.state++;
break;
case 2: // High initial gain
case 3:
case 4:
case 5:
lambda = 0.5;
K = 1-lambda;
K1 = 1-lambda*lambda;
K2 = (1-lambda)*(1-lambda);
K_thresh = 0.5;
tgt_meas.state++;
break;
default: // Continue tracking
lambda = 0.8;
//lambda = 1.5 - tgt_meas.Pd_image;
if(lambda > 0.9)
lambda = 0.9;
K = 1-lambda;
K1 = 1-lambda*lambda;
K2 = (1-lambda)*(1-lambda);
K_thresh = 0.4;
}
// Prediction errors
double pred_cx_err = tgt_meas.cx - tgt_meas.pred_cx;
double pred_cy_err = tgt_meas.cy - tgt_meas.pred_cy;
double pred_area_err = tgt_meas.area - tgt_meas.pred_area;
double pred_aspect_err = tgt_meas.aspect - tgt_meas.pred_aspect;
double pred_thresh_err = tgt_meas.thresh - tgt_meas.pred_thresh;
// Correction
tgt_est = tgt_meas;
tgt_est.cx = tgt_meas.pred_cx + K1 *
pred_cx_err;
tgt_est.vx = tgt_meas.vx + K2 *
pred_cx_err;
tgt_est.cy = tgt_meas.pred_cy + K1 *
pred_cy_err;
tgt_est.vy = tgt_meas.vy + K2 *
pred_cy_err;
tgt_est.area = tgt_meas.pred_area + K * pred_area_err;
tgt_est.aspect = tgt_meas.pred_aspect + K * pred_aspect_err;
tgt_est.thresh = tgt_meas.pred_thresh + K_thresh * pred_thresh_err;
if(tgt_est.thresh > max_thresh) tgt_est.thresh = max_thresh;
// Prediction
tgt_est.x += tgt_est.cx - tgt_meas.cx; // Required for drawing BBox
tgt_est.y += tgt_est.cy - tgt_meas.cy;
tgt_meas.vx = tgt_est.vx;
tgt_meas.vy = tgt_est.vy;
tgt_meas.pred_cx = tgt_est.cx + tgt_est.vx;
tgt_meas.pred_cy = tgt_est.cy + tgt_est.vy;
tgt_meas.pred_aspect= tgt_est.aspect;
tgt_meas.pred_area = tgt_est.area;
tgt_meas.pred_thresh= tgt_est.thresh;
return tgt_meas;
}
obj_est_array.clear();
for(i=0;i<obj_array.size();i++){
obj_pred = TrackObj(obj_array[i], obj_est);
obj_est_array.push_back(obj_est);
}
return i;
}
//============================================================================
// Name : First.cpp
// Author : Bilal
// Version : 1.0
//============================================================================
#include <iostream>
#include <vector>
#include "opencv2/opencv.hpp"
#include "Tracker.hpp"
#include "ImProcessing.hpp"
#include <opencv2/videoio.hpp>
int main() {
//VideoCapture cap("/home/bilal/Videos/Wildlife.wmv");
VideoCapture cap("/home/bilal/Videos/Birds1.avi");
int crop_top = 50;
int crop_bottom = 300;
int frame_width = cap.get(CAP_PROP_FRAME_WIDTH);
int frame_height = cap.get(CAP_PROP_FRAME_HEIGHT);
VideoWriter
video("Birds1_processed.wmv",VideoWriter::fourcc('W','M','V','1'),30,
//VideoWriter video("Birds1_processed.avi",VideoWriter::fourcc('M', 'J',
'P', 'G'),30,
Size(frame_width,(frame_height - crop_bottom)*2));
//VideoCapture cap(0);
if (!cap.isOpened())
return -1;
double n = cap.get(CAP_PROP_FRAME_COUNT);
double x = cap.get(CAP_PROP_FRAME_WIDTH);
double y = cap.get(CAP_PROP_FRAME_HEIGHT);
cap.set(CAP_PROP_FRAME_WIDTH, x);
cap.set(CAP_PROP_FRAME_HEIGHT, y);
double prev_n = 0;
cout << n << endl << x << "x" << y << endl;
cout << "Number of logical CPUs: " << getNumberOfCPUs() << endl;
obj_array_prev.clear();
for (; i < 350; i++) {
Mat frame_temp;
cap >> frame_temp;
Rect roi = Rect(0,crop_top,frame_width, frame_height-
crop_bottom);
Mat frame_in = frame_temp(roi);
Mat frame_disp;
frame_in.copyTo(frame_disp);
frame_disp.resize(frame_in.rows*2);
exit(0);
for (i = 1; i < 1000; i++) {
cap >> frame_in;
Preprocess(frame_in, frame_bin, base_thresh);
ExtractObjects(frame_bin, obj_array);
CorrelateObjs(obj_array_prev, obj_array);
TrackObjects(obj_array, obj_est_array);
obj_array_prev = obj_array;
DrawBBoxes(frame_in, Scalar(0, 0, 255), obj_array);
DrawBBoxes(frame_in, Scalar(255, 255, 0), obj_est_array);
PrintObjIDs(frame_in, Scalar(255, 0, 0), obj_array);
sprintf(s, "Frame no: %d", i);
putText(frame, s, Point(0, 50), FONT_HERSHEY_SIMPLEX, 0.6,
Scalar(255, 255, 255));
imshow("Processed Video", frame_bin);
imshow("Video", frame_in);
exit(0);
//************************
// Image Processing
//************************
tgt_meas = ExtractBestObject(frame, frame2, cands, tgt_pred,
thresh_dist);
n = cap.get(CAP_PROP_POS_MSEC);
//cout << n - prev_n << endl;
(waitKey(n - prev_n) <= 0);
//(waitKey(1)<=0);
prev_n = n;
return 0;
}