parent
e4f55a7ec0
commit
b4b63cd698
2 changed files with 148 additions and 79 deletions
@ -1,111 +1,180 @@ |
|||||||
#include "opencv2/imgproc/imgproc.hpp" |
#include "opencv2/imgproc/imgproc.hpp" |
||||||
#include "opencv2/objdetect/objdetect.hpp" |
#include "opencv2/objdetect/objdetect.hpp" |
||||||
#include "opencv2/highgui/highgui.hpp" |
#include "opencv2/highgui/highgui.hpp" |
||||||
|
#include <opencv2/softcascade/softcascade.hpp> |
||||||
|
|
||||||
#include <stdio.h> |
#include <iostream> |
||||||
#include <string.h> |
#include <vector> |
||||||
#include <ctype.h> |
#include <string> |
||||||
|
#include <fstream> |
||||||
|
|
||||||
using namespace cv; |
void filter_rects(const std::vector<cv::Rect>& candidates, std::vector<cv::Rect>& objects); |
||||||
using namespace std; |
|
||||||
|
|
||||||
// static void help()
|
|
||||||
// {
|
|
||||||
// printf(
|
|
||||||
// "\nDemonstrate the use of the HoG descriptor using\n"
|
|
||||||
// " HOGDescriptor::hog.setSVMDetector(HOGDescriptor::getDefaultPeopleDetector());\n"
|
|
||||||
// "Usage:\n"
|
|
||||||
// "./peopledetect (<image_filename> | <image_list>.txt)\n\n");
|
|
||||||
// }
|
|
||||||
|
|
||||||
int main(int argc, char** argv) |
int main(int argc, char** argv) |
||||||
{ |
{ |
||||||
Mat img; |
const std::string keys = |
||||||
FILE* f = 0; |
"{help h usage ? | | print this message and exit }" |
||||||
char _filename[1024]; |
"{cascade c | | path to cascade xml, if empty HOG detector will be executed }" |
||||||
|
"{frame f | | wildchart pattern to frame source}" |
||||||
|
"{min_scale |0.4 | minimum scale to detect }" |
||||||
|
"{max_scale |5.0 | maxamum scale to detect }" |
||||||
|
"{total_scales |55 | prefered number of scales between min and max }" |
||||||
|
"{write_file wf |0 | write to .txt. Disabled by default.}" |
||||||
|
"{write_image wi |0 | write to image. Disabled by default.}" |
||||||
|
"{show_image si |1 | show image. Enabled by default.}" |
||||||
|
"{threshold thr |-1 | detection threshold. Detections with score less then threshold will be ignored.}" |
||||||
|
; |
||||||
|
|
||||||
|
cv::CommandLineParser parser(argc, argv, keys); |
||||||
|
parser.about("Soft cascade training application."); |
||||||
|
|
||||||
if( argc == 1 ) |
if (parser.has("help")) |
||||||
{ |
{ |
||||||
printf("Usage: peopledetect (<image_filename> | <image_list>.txt)\n"); |
parser.printMessage(); |
||||||
return 0; |
return 0; |
||||||
} |
} |
||||||
img = imread(argv[1]); |
|
||||||
|
|
||||||
if( img.data ) |
if (!parser.check()) |
||||||
{ |
{ |
||||||
strcpy(_filename, argv[1]); |
parser.printErrors(); |
||||||
|
return 1; |
||||||
|
} |
||||||
|
|
||||||
|
int wf = parser.get<int>("write_file"); |
||||||
|
if (wf) std::cout << "resulte will be stored to .txt file with the same name as image." << std::endl; |
||||||
|
|
||||||
|
int wi = parser.get<int>("write_image"); |
||||||
|
if (wi) std::cout << "resulte will be stored to image with the same name as input plus dt." << std::endl; |
||||||
|
|
||||||
|
int si = parser.get<int>("show_image"); |
||||||
|
|
||||||
|
float minScale = parser.get<float>("min_scale"); |
||||||
|
float maxScale = parser.get<float>("max_scale"); |
||||||
|
int scales = parser.get<int>("total_scales"); |
||||||
|
int thr = parser.get<int>("threshold"); |
||||||
|
|
||||||
|
cv::HOGDescriptor hog; |
||||||
|
cv::softcascade::Detector cascade; |
||||||
|
|
||||||
|
bool useHOG = false; |
||||||
|
std::string cascadePath = parser.get<std::string>("cascade"); |
||||||
|
if (cascadePath.empty()) |
||||||
|
{ |
||||||
|
useHOG = true; |
||||||
|
hog.setSVMDetector(cv::HOGDescriptor::getDefaultPeopleDetector()); |
||||||
|
std::cout << "going to use HOG detector." << std::endl; |
||||||
} |
} |
||||||
else |
else |
||||||
{ |
{ |
||||||
f = fopen(argv[1], "rt"); |
cv::FileStorage fs(cascadePath, cv::FileStorage::READ); |
||||||
if(!f) |
if( !fs.isOpened()) |
||||||
{ |
{ |
||||||
fprintf( stderr, "ERROR: the specified file could not be loaded\n"); |
std::cout << "Soft Cascade file " << cascadePath << " can't be opened." << std::endl << std::flush; |
||||||
return -1; |
return 1; |
||||||
|
} |
||||||
|
|
||||||
|
cascade = cv::softcascade::Detector(minScale, maxScale, scales, cv::softcascade::Detector::DOLLAR); |
||||||
|
|
||||||
|
if (!cascade.load(fs.getFirstTopLevelNode())) |
||||||
|
{ |
||||||
|
std::cout << "Soft Cascade can't be parsed." << std::endl << std::flush; |
||||||
|
return 1; |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
HOGDescriptor hog; |
std::string src = parser.get<std::string>("frame"); |
||||||
hog.setSVMDetector(HOGDescriptor::getDefaultPeopleDetector()); |
std::vector<std::string> frames; |
||||||
namedWindow("people detector", 1); |
cv::glob(parser.get<std::string>("frame"), frames); |
||||||
|
std::cout << "collected " << src << " " << frames.size() << " frames." << std::endl; |
||||||
|
|
||||||
for(;;) |
for (int i = 0; i < (int)frames.size(); ++i) |
||||||
{ |
{ |
||||||
char* filename = _filename; |
std::string& frame_sourse = frames[i]; |
||||||
if(f) |
cv::Mat frame = cv::imread(frame_sourse); |
||||||
|
|
||||||
|
if(frame.empty()) |
||||||
{ |
{ |
||||||
if(!fgets(filename, (int)sizeof(_filename)-2, f)) |
std::cout << "Frame source " << frame_sourse << " can't be opened." << std::endl << std::flush; |
||||||
break; |
|
||||||
//while(*filename && isspace(*filename))
|
|
||||||
// ++filename;
|
|
||||||
if(filename[0] == '#') |
|
||||||
continue; |
continue; |
||||||
int l = (int)strlen(filename); |
|
||||||
while(l > 0 && isspace(filename[l-1])) |
|
||||||
--l; |
|
||||||
filename[l] = '\0'; |
|
||||||
img = imread(filename); |
|
||||||
} |
} |
||||||
printf("%s:\n", filename); |
|
||||||
if(!img.data) |
|
||||||
continue; |
|
||||||
|
|
||||||
fflush(stdout); |
std::ofstream myfile; |
||||||
vector<Rect> found, found_filtered; |
if (wf) |
||||||
double t = (double)getTickCount(); |
myfile.open((frame_sourse.replace(frame_sourse.end() - 3, frame_sourse.end(), "txt")).c_str(), std::ios::out); |
||||||
|
|
||||||
|
////
|
||||||
|
if (useHOG) |
||||||
|
{ |
||||||
|
std::vector<cv::Rect> found, found_filtered; |
||||||
// run the detector with default parameters. to get a higher hit-rate
|
// run the detector with default parameters. to get a higher hit-rate
|
||||||
// (and more false alarms, respectively), decrease the hitThreshold and
|
// (and more false alarms, respectively), decrease the hitThreshold and
|
||||||
// groupThreshold (set groupThreshold to 0 to turn off the grouping completely).
|
// groupThreshold (set groupThreshold to 0 to turn off the grouping completely).
|
||||||
hog.detectMultiScale(img, found, 0, Size(8,8), Size(32,32), 1.05, 2); |
hog.detectMultiScale(frame, found, 0, cv::Size(8,8), cv::Size(32,32), 1.05, 2); |
||||||
t = (double)getTickCount() - t; |
|
||||||
printf("tdetection time = %gms\n", t*1000./cv::getTickFrequency()); |
filter_rects(found, found_filtered); |
||||||
size_t i, j; |
std::cout << "collected: " << (int)found_filtered.size() << " detections." << std::endl; |
||||||
for( i = 0; i < found.size(); i++ ) |
|
||||||
|
for (size_t ff = 0; ff < found_filtered.size(); ++ff) |
||||||
{ |
{ |
||||||
Rect r = found[i]; |
cv::Rect r = found_filtered[ff]; |
||||||
for( j = 0; j < found.size(); j++ ) |
cv::rectangle(frame, r.tl(), r.br(), cv::Scalar(0,255,0), 3); |
||||||
if( j != i && (r & found[j]) == r) |
|
||||||
break; |
if (wf) myfile << r.x << "," << r.y << "," << r.width << "," << r.height << "," << 0.f << "\n"; |
||||||
if( j == found.size() ) |
} |
||||||
found_filtered.push_back(r); |
|
||||||
} |
} |
||||||
for( i = 0; i < found_filtered.size(); i++ ) |
else |
||||||
|
{ |
||||||
|
std::vector<cv::softcascade::Detection> objects; |
||||||
|
cascade.detect(frame, cv::noArray(), objects); |
||||||
|
std::cout << "collected: " << (int)objects.size() << " detections." << std::endl; |
||||||
|
|
||||||
|
for (int obj = 0; obj < (int)objects.size(); ++obj) |
||||||
{ |
{ |
||||||
Rect r = found_filtered[i]; |
cv::softcascade::Detection d = objects[obj]; |
||||||
// the HOG detector returns slightly larger rectangles than the real objects.
|
|
||||||
// so we slightly shrink the rectangles to get a nicer output.
|
if(d.confidence > thr) |
||||||
r.x += cvRound(r.width*0.1); |
{ |
||||||
r.width = cvRound(r.width*0.8); |
float b = d.confidence * 1.5f; |
||||||
r.y += cvRound(r.height*0.07); |
|
||||||
r.height = cvRound(r.height*0.8); |
std::stringstream conf(std::stringstream::in | std::stringstream::out); |
||||||
rectangle(img, r.tl(), r.br(), cv::Scalar(0,255,0), 3); |
conf << d.confidence; |
||||||
|
|
||||||
|
cv::rectangle(frame, cv::Rect(d.bb.x, d.bb.y, d.bb.width, d.bb.height), cv::Scalar(b, 0, 255 - b, 255), 2); |
||||||
|
cv::putText(frame, conf.str() , cv::Point(d.bb.x + 10, d.bb.y - 5),1, 1.1, cv::Scalar(25, 133, 255, 0), 1, CV_AA); |
||||||
|
|
||||||
|
if (wf) |
||||||
|
myfile << d.bb.x << "," << d.bb.y << "," |
||||||
|
<< d.bb.width << "," << d.bb.height << "," << d.confidence << "\n"; |
||||||
|
} |
||||||
} |
} |
||||||
imshow("people detector", img); |
|
||||||
int c = waitKey(0) & 255; |
|
||||||
if( c == 'q' || c == 'Q' || !f) |
|
||||||
break; |
|
||||||
} |
} |
||||||
if(f) |
|
||||||
fclose(f); |
if (wi) cv::imwrite(frame_sourse + ".dt.png", frame); |
||||||
|
if (wf) myfile.close(); |
||||||
|
|
||||||
|
if (si) |
||||||
|
{ |
||||||
|
cv::imshow("pedestrian detector", frame); |
||||||
|
cv::waitKey(10); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (si) cv::waitKey(0); |
||||||
return 0; |
return 0; |
||||||
} |
} |
||||||
|
|
||||||
|
void filter_rects(const std::vector<cv::Rect>& candidates, std::vector<cv::Rect>& objects) |
||||||
|
{ |
||||||
|
size_t i, j; |
||||||
|
for (i = 0; i < candidates.size(); ++i) |
||||||
|
{ |
||||||
|
cv::Rect r = candidates[i]; |
||||||
|
|
||||||
|
for (j = 0; j < candidates.size(); ++j) |
||||||
|
if (j != i && (r & candidates[j]) == r) |
||||||
|
break; |
||||||
|
|
||||||
|
if (j == candidates.size()) |
||||||
|
objects.push_back(r); |
||||||
|
} |
||||||
|
} |
||||||
|
Loading…
Reference in new issue