Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 9 years ago.
Improve this question
I need to create Header file mainCalib.h from the mainCalib.cpp file
the mainCalib.cpp file include calibration Sample of opencv ..
so finally I can execute the program from main.cpp file:
this is mainCalib.cpp file:
#include <iostream>
#include <sstream>
#include <time.h>
#include <stdio.h>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/calib3d/calib3d.hpp>
#include <opencv2/highgui/highgui.hpp>
#ifndef _CRT_SECURE_NO_WARNINGS
# define _CRT_SECURE_NO_WARNINGS
#endif
#include "mainCalib.h"
using namespace cv;
using namespace std;
void help()
{
cout << "This is a camera calibration sample." << endl
<< "Usage: calibration configurationFile" << endl
<< "Near the sample file you'll find the configuration file, which has detailed help of "
"how to edit it. It may be any OpenCV supported file format XML/YAML." << endl;
}
class Settings
{
public:
Settings() : goodInput(false) {}
enum Pattern { NOT_EXISTING, CHESSBOARD, CIRCLES_GRID, ASYMMETRIC_CIRCLES_GRID };
enum InputType {INVALID, CAMERA, VIDEO_FILE, IMAGE_LIST};
void write(FileStorage& fs) const //Write serialization for this class
{
fs << "{" << "BoardSize_Width" << boardSize.width
<< "BoardSize_Height" << boardSize.height
<< "Square_Size" << squareSize
<< "Calibrate_Pattern" << patternToUse
<< "Calibrate_NrOfFrameToUse" << nrFrames
<< "Calibrate_FixAspectRatio" << aspectRatio
<< "Calibrate_AssumeZeroTangentialDistortion" << calibZeroTangentDist
<< "Calibrate_FixPrincipalPointAtTheCenter" << calibFixPrincipalPoint
<< "Write_DetectedFeaturePoints" << bwritePoints
<< "Write_extrinsicParameters" << bwriteExtrinsics
<< "Write_outputFileName" << outputFileName
<< "Show_UndistortedImage" << showUndistorsed
<< "Input_FlipAroundHorizontalAxis" << flipVertical
<< "Input_Delay" << delay
<< "Input" << input
<< "}";
}
void read(const FileNode& node) //Read serialization for this class
{
node["BoardSize_Width" ] >> boardSize.width;
node["BoardSize_Height"] >> boardSize.height;
node["Calibrate_Pattern"] >> patternToUse;
node["Square_Size"] >> squareSize;
node["Calibrate_NrOfFrameToUse"] >> nrFrames;
node["Calibrate_FixAspectRatio"] >> aspectRatio;
node["Write_DetectedFeaturePoints"] >> bwritePoints;
node["Write_extrinsicParameters"] >> bwriteExtrinsics;
node["Write_outputFileName"] >> outputFileName;
node["Calibrate_AssumeZeroTangentialDistortion"] >> calibZeroTangentDist;
node["Calibrate_FixPrincipalPointAtTheCenter"] >> calibFixPrincipalPoint;
node["Input_FlipAroundHorizontalAxis"] >> flipVertical;
node["Show_UndistortedImage"] >> showUndistorsed;
node["Input"] >> input;
node["Input_Delay"] >> delay;
interprate();
}
void interprate()
{
goodInput = true;
if (boardSize.width <= 0 || boardSize.height <= 0)
{
cerr << "Invalid Board size: " << boardSize.width << " " << boardSize.height << endl;
goodInput = false;
}
if (squareSize <= 10e-6)
{
cerr << "Invalid square size " << squareSize << endl;
goodInput = false;
}
if (nrFrames <= 0)
{
cerr << "Invalid number of frames " << nrFrames << endl;
goodInput = false;
}
if (input.empty()) // Check for valid input
inputType = INVALID;
else
{
if (input[0] >= '0' && input[0] <= '9')
{
stringstream ss(input);
ss >> cameraID;
inputType = CAMERA;
}
else
{
if (readStringList(input, imageList))
{
inputType = IMAGE_LIST;
nrFrames = (nrFrames < (int)imageList.size()) ? nrFrames : (int)imageList.size();
}
else
inputType = VIDEO_FILE;
}
if (inputType == CAMERA)
inputCapture.open(cameraID);
if (inputType == VIDEO_FILE)
inputCapture.open(input);
if (inputType != IMAGE_LIST && !inputCapture.isOpened())
inputType = INVALID;
}
if (inputType == INVALID)
{
cerr << " Inexistent input: " << input;
goodInput = false;
}
flag = 0;
if(calibFixPrincipalPoint) flag |= CV_CALIB_FIX_PRINCIPAL_POINT;
if(calibZeroTangentDist) flag |= CV_CALIB_ZERO_TANGENT_DIST;
if(aspectRatio) flag |= CV_CALIB_FIX_ASPECT_RATIO;
calibrationPattern = NOT_EXISTING;
if (!patternToUse.compare("CHESSBOARD")) calibrationPattern = CHESSBOARD;
if (!patternToUse.compare("CIRCLES_GRID")) calibrationPattern = CIRCLES_GRID;
if (!patternToUse.compare("ASYMMETRIC_CIRCLES_GRID")) calibrationPattern = ASYMMETRIC_CIRCLES_GRID;
if (calibrationPattern == NOT_EXISTING)
{
cerr << " Inexistent camera calibration mode: " << patternToUse << endl;
goodInput = false;
}
atImageList = 0;
}
Mat nextImage()
{
Mat result;
if( inputCapture.isOpened() )
{
Mat view0;
inputCapture >> view0;
view0.copyTo(result);
}
else if( atImageList < (int)imageList.size() )
result = imread(imageList[atImageList++], CV_LOAD_IMAGE_COLOR);
return result;
}
static bool readStringList( const string& filename, vector<string>& l )
{
l.clear();
FileStorage fs(filename, FileStorage::READ);
if( !fs.isOpened() )
return false;
FileNode n = fs.getFirstTopLevelNode();
if( n.type() != FileNode::SEQ )
return false;
FileNodeIterator it = n.begin(), it_end = n.end();
for( ; it != it_end; ++it )
l.push_back((string)*it);
return true;
}
public:
Size boardSize; // The size of the board -> Number of items by width and height
Pattern calibrationPattern;// One of the Chessboard, circles, or asymmetric circle pattern
float squareSize; // The size of a square in your defined unit (point, millimeter,etc).
int nrFrames; // The number of frames to use from the input for calibration
float aspectRatio; // The aspect ratio
int delay; // In case of a video input
bool bwritePoints; // Write detected feature points
bool bwriteExtrinsics; // Write extrinsic parameters
bool calibZeroTangentDist; // Assume zero tangential distortion
bool calibFixPrincipalPoint;// Fix the principal point at the center
bool flipVertical; // Flip the captured images around the horizontal axis
string outputFileName; // The name of the file where to write
bool showUndistorsed; // Show undistorted images after calibration
string input; // The input ->
int cameraID;
vector<string> imageList;
int atImageList;
VideoCapture inputCapture;
InputType inputType;
bool goodInput;
int flag;
private:
string patternToUse;
};
static void read(const FileNode& node, Settings& x, const Settings& default_value = Settings())
{
if(node.empty())
x = default_value;
else
x.read(node);
}
enum { DETECTION = 0, CAPTURING = 1, CALIBRATED = 2 };
bool runCalibrationAndSave(Settings& s, Size imageSize, Mat& cameraMatrix, Mat& distCoeffs,
vector<vector<Point2f> > imagePoints );
int mainn(int argc, char* argv[])
{
help();
Settings s;
const string inputSettingsFile = argc > 1 ? argv[1] : "D:\\e+v\\Projekte\\Calibration_Test1\\Calibration_Test1\\in_VID5.xml";
FileStorage fs(inputSettingsFile, FileStorage::READ); // Read the settings
if (!fs.isOpened())
{
cout << "Could not open the configuration file: \"" << inputSettingsFile << "\"" << endl;
return -1;
}
fs["Settings"] >> s;
fs.release(); // close Settings file
if (!s.goodInput)
{
cout << "Invalid input detected. Application stopping. " << endl;
return -1;
}
vector<vector<Point2f> > imagePoints;
Mat cameraMatrix, distCoeffs;
Size imageSize;
int mode = s.inputType == Settings::IMAGE_LIST ? CAPTURING : DETECTION;
clock_t prevTimestamp = 0;
const Scalar RED(0,0,255), GREEN(0,255,0);
const char ESC_KEY = 27;
for(int i = 0;;++i)
{
Mat view;
bool blinkOutput = false;
view = s.nextImage();
//----- If no more image, or got enough, then stop calibration and show result -------------
if( mode == CAPTURING && imagePoints.size() >= (unsigned)s.nrFrames )
{
if( runCalibrationAndSave(s, imageSize, cameraMatrix, distCoeffs, imagePoints))
mode = CALIBRATED;
else
mode = DETECTION;
}
if(view.empty()) // If no more images then run calibration, save and stop loop.
{
if( imagePoints.size() > 0 )
runCalibrationAndSave(s, imageSize, cameraMatrix, distCoeffs, imagePoints);
break;
}
imageSize = view.size(); // Format input image.
if( s.flipVertical ) flip( view, view, 0 );
vector<Point2f> pointBuf;
bool found;
switch( s.calibrationPattern ) // Find feature points on the input format
{
case Settings::CHESSBOARD:
found = findChessboardCorners( view, s.boardSize, pointBuf,
CV_CALIB_CB_ADAPTIVE_THRESH | CV_CALIB_CB_FAST_CHECK | CV_CALIB_CB_NORMALIZE_IMAGE);
break;
case Settings::CIRCLES_GRID:
found = findCirclesGrid( view, s.boardSize, pointBuf );
break;
case Settings::ASYMMETRIC_CIRCLES_GRID:
found = findCirclesGrid( view, s.boardSize, pointBuf, CALIB_CB_ASYMMETRIC_GRID );
break;
default:
found = false;
break;
}
if ( found) // If done with success,
{
// improve the found corners' coordinate accuracy for chessboard
if( s.calibrationPattern == Settings::CHESSBOARD)
{
Mat viewGray;
cvtColor(view, viewGray, COLOR_BGR2GRAY);
cornerSubPix( viewGray, pointBuf, Size(11,11),
Size(-1,-1), TermCriteria( CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 30, 0.1 ));
}
if( mode == CAPTURING && // For camera only take new samples after delay time
(!s.inputCapture.isOpened() || clock() - prevTimestamp > s.delay*1e-3*CLOCKS_PER_SEC) )
{
imagePoints.push_back(pointBuf);
prevTimestamp = clock();
blinkOutput = s.inputCapture.isOpened();
}
// Draw the corners.
drawChessboardCorners( view, s.boardSize, Mat(pointBuf), found );
}
//----------------------------- Output Text ------------------------------------------------
string msg = (mode == CAPTURING) ? "100/100" :
mode == CALIBRATED ? "Calibrated" : "Press 'g' to start";
int baseLine = 0;
Size textSize = getTextSize(msg, 1, 1, 1, &baseLine);
Point textOrigin(view.cols - 2*textSize.width - 10, view.rows - 2*baseLine - 10);
if( mode == CAPTURING )
{
if(s.showUndistorsed)
msg = format( "%d/%d Undist", (int)imagePoints.size(), s.nrFrames );
else
msg = format( "%d/%d", (int)imagePoints.size(), s.nrFrames );
}
putText( view, msg, textOrigin, 1, 1, mode == CALIBRATED ? GREEN : RED);
if( blinkOutput )
bitwise_not(view, view);
//------------------------- Video capture output undistorted ------------------------------
if( mode == CALIBRATED && s.showUndistorsed )
{
Mat temp = view.clone();
undistort(temp, view, cameraMatrix, distCoeffs);
}
//------------------------------ Show image and check for input commands -------------------
imshow("Image View", view);
char key = (char)waitKey(s.inputCapture.isOpened() ? 50 : s.delay);
if( key == ESC_KEY )
break;
if( key == 'u' && mode == CALIBRATED )
s.showUndistorsed = !s.showUndistorsed;
if( s.inputCapture.isOpened() && key == 'g' )
{
mode = CAPTURING;
imagePoints.clear();
}
}
// -----------------------Show the undistorted image for the image list ------------------------
if( s.inputType == Settings::IMAGE_LIST && s.showUndistorsed )
{
Mat view, rview, map1, map2;
initUndistortRectifyMap(cameraMatrix, distCoeffs, Mat(),
getOptimalNewCameraMatrix(cameraMatrix, distCoeffs, imageSize, 1, imageSize, 0),
imageSize, CV_16SC2, map1, map2);
for(int i = 0; i < (int)s.imageList.size(); i++ )
{
view = imread(s.imageList[i], 1);
if(view.empty())
continue;
remap(view, rview, map1, map2, INTER_LINEAR);
imshow("Image View", rview);
char c = (char)waitKey();
if( c == ESC_KEY || c == 'q' || c == 'Q' )
break;
}
}
return 0;
}
static double computeReprojectionErrors( const vector<vector<Point3f> >& objectPoints,
const vector<vector<Point2f> >& imagePoints,
const vector<Mat>& rvecs, const vector<Mat>& tvecs,
const Mat& cameraMatrix , const Mat& distCoeffs,
vector<float>& perViewErrors)
{
vector<Point2f> imagePoints2;
int i, totalPoints = 0;
double totalErr = 0, err;
perViewErrors.resize(objectPoints.size());
for( i = 0; i < (int)objectPoints.size(); ++i )
{
projectPoints( Mat(objectPoints[i]), rvecs[i], tvecs[i], cameraMatrix,
distCoeffs, imagePoints2);
err = norm(Mat(imagePoints[i]), Mat(imagePoints2), CV_L2);
int n = (int)objectPoints[i].size();
perViewErrors[i] = (float) std::sqrt(err*err/n);
totalErr += err*err;
totalPoints += n;
}
return std::sqrt(totalErr/totalPoints);
}
static void calcBoardCornerPositions(Size boardSize, float squareSize, vector<Point3f>& corners,
Settings::Pattern patternType /*= Settings::CHESSBOARD*/)
{
corners.clear();
switch(patternType)
{
case Settings::CHESSBOARD:
case Settings::CIRCLES_GRID:
for( int i = 0; i < boardSize.height; ++i )
for( int j = 0; j < boardSize.width; ++j )
corners.push_back(Point3f(float( j*squareSize ), float( i*squareSize ), 0));
break;
case Settings::ASYMMETRIC_CIRCLES_GRID:
for( int i = 0; i < boardSize.height; i++ )
for( int j = 0; j < boardSize.width; j++ )
corners.push_back(Point3f(float((2*j + i % 2)*squareSize), float(i*squareSize), 0));
break;
default:
break;
}
}
static bool runCalibration( Settings& s, Size& imageSize, Mat& cameraMatrix, Mat& distCoeffs,
vector<vector<Point2f> > imagePoints, vector<Mat>& rvecs, vector<Mat>& tvecs,
vector<float>& reprojErrs, double& totalAvgErr)
{
cameraMatrix = Mat::eye(3, 3, CV_64F);
if( s.flag & CV_CALIB_FIX_ASPECT_RATIO )
cameraMatrix.at<double>(0,0) = 1.0;
distCoeffs = Mat::zeros(8, 1, CV_64F);
vector<vector<Point3f> > objectPoints(1);
calcBoardCornerPositions(s.boardSize, s.squareSize, objectPoints[0], s.calibrationPattern);
objectPoints.resize(imagePoints.size(),objectPoints[0]);
//Find intrinsic and extrinsic camera parameters
double rms = calibrateCamera(objectPoints, imagePoints, imageSize, cameraMatrix,
distCoeffs, rvecs, tvecs, s.flag|CV_CALIB_FIX_K4|CV_CALIB_FIX_K5);
cout << "Re-projection error reported by calibrateCamera: "<< rms << endl;
bool ok = checkRange(cameraMatrix) && checkRange(distCoeffs);
totalAvgErr = computeReprojectionErrors(objectPoints, imagePoints,
rvecs, tvecs, cameraMatrix, distCoeffs, reprojErrs);
return ok;
}
// Print camera parameters to the output file
static void saveCameraParams( Settings& s, Size& imageSize, Mat& cameraMatrix, Mat& distCoeffs,
const vector<Mat>& rvecs, const vector<Mat>& tvecs,
const vector<float>& reprojErrs, const vector<vector<Point2f> >& imagePoints,
double totalAvgErr )
{
FileStorage fs( s.outputFileName, FileStorage::WRITE );
time_t tm;
time( &tm );
struct tm *t2 = localtime( &tm );
char buf[1024];
strftime( buf, sizeof(buf)-1, "%c", t2 );
fs << "calibration_Time" << buf;
if( !rvecs.empty() || !reprojErrs.empty() )
fs << "nrOfFrames" << (int)std::max(rvecs.size(), reprojErrs.size());
fs << "image_Width" << imageSize.width;
fs << "image_Height" << imageSize.height;
fs << "board_Width" << s.boardSize.width;
fs << "board_Height" << s.boardSize.height;
fs << "square_Size" << s.squareSize;
if( s.flag & CV_CALIB_FIX_ASPECT_RATIO )
fs << "FixAspectRatio" << s.aspectRatio;
if( s.flag )
{
sprintf( buf, "flags: %s%s%s%s",
s.flag & CV_CALIB_USE_INTRINSIC_GUESS ? " +use_intrinsic_guess" : "",
s.flag & CV_CALIB_FIX_ASPECT_RATIO ? " +fix_aspectRatio" : "",
s.flag & CV_CALIB_FIX_PRINCIPAL_POINT ? " +fix_principal_point" : "",
s.flag & CV_CALIB_ZERO_TANGENT_DIST ? " +zero_tangent_dist" : "" );
cvWriteComment( *fs, buf, 0 );
}
fs << "flagValue" << s.flag;
fs << "Camera_Matrix" << cameraMatrix;
fs << "Distortion_Coefficients" << distCoeffs;
fs << "Avg_Reprojection_Error" << totalAvgErr;
if( !reprojErrs.empty() )
fs << "Per_View_Reprojection_Errors" << Mat(reprojErrs);
if( !rvecs.empty() && !tvecs.empty() )
{
CV_Assert(rvecs[0].type() == tvecs[0].type());
Mat bigmat((int)rvecs.size(), 6, rvecs[0].type());
for( int i = 0; i < (int)rvecs.size(); i++ )
{
Mat r = bigmat(Range(i, i+1), Range(0,3));
Mat t = bigmat(Range(i, i+1), Range(3,6));
CV_Assert(rvecs[i].rows == 3 && rvecs[i].cols == 1);
CV_Assert(tvecs[i].rows == 3 && tvecs[i].cols == 1);
//*.t() is MatExpr (not Mat) so we can use assignment operator
r = rvecs[i].t();
t = tvecs[i].t();
}
cvWriteComment( *fs, "a set of 6-tuples (rotation vector + translation vector) for each view", 0 );
fs << "Extrinsic_Parameters" << bigmat;
}
if( !imagePoints.empty() )
{
Mat imagePtMat((int)imagePoints.size(), (int)imagePoints[0].size(), CV_32FC2);
for( int i = 0; i < (int)imagePoints.size(); i++ )
{
Mat r = imagePtMat.row(i).reshape(2, imagePtMat.cols);
Mat imgpti(imagePoints[i]);
imgpti.copyTo(r);
}
fs << "Image_points" << imagePtMat;
}
}
bool runCalibrationAndSave(Settings& s, Size imageSize, Mat& cameraMatrix, Mat& distCoeffs,vector<vector<Point2f> > imagePoints )
{
vector<Mat> rvecs, tvecs;
vector<float> reprojErrs;
double totalAvgErr = 0;
bool ok = runCalibration(s,imageSize, cameraMatrix, distCoeffs, imagePoints, rvecs, tvecs,
reprojErrs, totalAvgErr);
cout << (ok ? "Calibration succeeded" : "Calibration failed")
<< ". avg re projection error = " << totalAvgErr ;
if( ok )
saveCameraParams( s, imageSize, cameraMatrix, distCoeffs, rvecs ,tvecs, reprojErrs,
imagePoints, totalAvgErr);
return ok;
}
and here is main.cpp file:
#include<iostream>
#include"mainCalib.h"
using namespace std;
int main()
{
return 0;
}
So please can anyone help me to create the code of mainCalib.h file from mainCalib.cpp
classes and functions!
I tried such as followings but I have much Errors:
mainCalib.h file:
void help();
class Settings;
static void read(const FileNode& , Settings& , const Settings& );
bool runCalibrationAndSave (Settings& s, Size imageSize, Mat& cameraMatrix, Mat& distCoeffs, vector<vector<Point2f>> imagePoints);
int mainn(int argc, char* argv[])
static double computeReprojectionErrors( const vector<vector<Point3f> >& objectPoints,const vector<vector<Point2f> >& imagePoints,const vector<Mat>& rvecs, const vector<Mat>& tvecs,const Mat& cameraMatrix , const Mat& distCoeffs,vector<float>& perViewErrors);
static void calcBoardCornerPositions(cv::Size , float , vector<Point3f>& ,
Settings::Pattern /*= Settings::CHESSBOARD*/);
static bool runCalibration( Settings& s, Size& , Mat& , Mat& ,vector<vector<Point2f> > , vector<Mat>& , vector<Mat>& ,vector<float>& , double& );
static void saveCameraParams( Settings& , cv::Size& , Mat& , Mat& ,
const vector<Mat>& , const vector<Mat>& ,
const vector<float>& , const vector<vector<Point2f> >& ,
double );
First read about include guards.
Then you put the actual class definition in the header file.
Then you put the class function implementation in the source file.
Short example
Header file
#ifndef HEADER_FILE_H
#define HEADER_FILE_H
class MyClass
{
public:
MyClass(int val);
~MyClass();
void some_function();
private:
int value;
};
#endif // HEADER_FILE_H
Source file
#include <iostream>
#include "header_file.h"
MyClass::MyClass(int val)
: value(val)
{
}
MyClass::~MyClass()
{
}
void MyClass::some_function()
{
std::cout << "value is " << value << '\n';
}
Main source file
#include "header_file.h"
int main()
{
MyClass my_object(5);
my_object.some_function();
}
Also note that you can't have static function in the file scope if you expect them to be called from outside that source file. Making a function static restricts linkage to the translation unit it is defined in.
Related
I am writing an interface for line detection in SFML and OpenCV in C++; I have 2 classes: Interface and ImageProccessing. I need 2 while loops (one for drawing whole interface on screen and other for line detecting) so I decided to use threads. I created a new thread in Interface constructor using:
ImageProccessingThread = new std::thread(&ImageProccessing::start, context.imageproc, toString(getContext().connection->getIP()), getContext().connection->getPort());
It needs 2 arguments (IP and Port of webcam). The thread is working correctly, cause when I am displaying windows from it, everything is fine. The problem is in the main thread. I want to copy cv::Mat from ImageProccessing class, convert it into SFML image and display. I handled converting and displaying (tested on another webcam image captured in main thread). But I can't copy the Mat from ImageProccessingThread and use it in main thread. Using:
getContext().imageproc->getOriginal().copyTo(frameRGB);
if (frameRGB.empty())
Says there is no image - it's empty. Just like threads works on separate data. I was thinking it's synchronisation problem, so I tried to use mutex. In ImageProccessing class I added:
mtx.lock();
result.copyTo(imgResult);
imgThresholded.copyTo(imgThresh);
mtx.unlock();
But it gives nothing. What do I do wrong?
EDIT:
More explanation about copying
The copy takes part in Interface class.
Interface:
cv::Mat frameRGB, frameRGBA;
getContext().imageproc->getOriginal().copyTo(frameRGB);
if (frameRGB.empty())
{
std::cout << "Can't copy" << std::endl;
system("PAUSE");
return;
}
cv::cvtColor(frameRGB, frameRGBA, cv::COLOR_BGR2RGBA);
camImage.create(frameRGBA.cols, frameRGBA.rows, frameRGBA.ptr());
if (!camTexture.loadFromImage(camImage))
{
std::cout << "No image" << std::endl;
system("PAUSE");
return;
}
camSprite.setTexture(camTexture);
camSprite.setPosition(1214.f, 30.f);
While I get cv::Mat from ImageProccessing getter
ImageProccessing:
ImageProccessing.hpp:
#pragma once
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
#include <opencv2/opencv.hpp>
#include <math.h>
#include <SFML/Network.hpp>
#include <fstream>
class ImageProccessing
{
public:
ImageProccessing();
~ImageProccessing();
sf::Int16 doProccessing();
void setup();
void number_of_lines(int*, cv::Mat*, int, int, bool);
bool zeros(float min);
void tresh();
void update(cv::Mat imgOriginal);
int start(std::string, unsigned short);
void Parameters_load(struct Config);
struct Config Parameters_check();
void show(bool);
cv::Mat getOriginal();
cv::Mat getThreshholded();
bool getStarted();
void changeTest(bool change);
bool getTest();
private:
bool Test;
bool isStarted;
cv::VideoCapture cap;
cv::Mat imgOriginal;
cv::Mat roi_left;
cv::Mat roi_right;
cv::Mat contours1;
cv::Mat imgThresholded;
cv::Mat result;
cv::Mat imgResult;
cv::Mat imgThresh;
int iLowH;
int iHighH;
int iLowS;
int iHighS;
int iLowV;
int iHighV;
int max_angle;
int min_angle;
int mid_angle_left;
int mid_angle_right;
int point_height;
float cut_off;
int houghVote_left;
int houghVote_right;
int size_destruct;
int size_fill;
void average(float, float);
FILE* files;
std::vector<cv::Vec2f> lines;
};
Parts of ImageProccessing.cpp:
cv::Mat ImageProccessing::getOriginal()
{
return imgResult;
}
sf::Int16 ImageProccessing::doProccessing()
{
sf::Int16 value = 0;
std::vector<Vec2f> lines_left;
std::vector<Vec2f> lines_right;
roi_left = contours1(Rect(0, 0, int(float(contours1.cols) *cut_off), imgOriginal.rows));
roi_right = contours1(Rect(int(float(contours1.cols) *(1 - cut_off)), 0, int(float(contours1.cols)*cut_off), imgOriginal.rows));
lines = lines_left;
this->number_of_lines(&houghVote_left, &roi_left, min_angle, mid_angle_left, true);
lines_left = lines;
lines = lines_right;
this->number_of_lines(&houghVote_right, &roi_right, mid_angle_right, max_angle, false);
lines_right = lines;
std::cout << "houghVote" << houghVote_left << " " << houghVote_right << "\n";
std::cout << "lines" << lines_left.size() << "lines1" << lines_right.size() << "\n";
std::cout << "min " << min_angle * PI / 180 << ", max" << max_angle * PI / 180 << "\n";
//fprintf(files, "houghVote %d %d lines %d lines1 %d min %f max %f", houghVote_left, houghVote_right, lines_left.size(), lines_right.size(), min_angle * PI / 180, max_angle * PI / 180);
imgOriginal.copyTo(result);
if (lines_left.size() < 30) {
lines = lines_left;
average(10, 1.5);
lines_left = lines;
}
if (lines_right.size() < 30) {
lines = lines_right;
average(10, 1.5);
lines_right = lines;
}
unsigned __int64 begin = 0;
Mat hough(imgOriginal.size(), CV_8U, Scalar(0));
Vec2f closest;
float min_distance_left = float(result.cols) / 2;
while (begin < lines_left.size()) {
float rho = lines_left[begin][0]; // first element is distance rho
float theta = lines_left[begin][1]; // second element is angle theta
float a = -(cos(theta) / sin(theta));
float b = rho / sin(theta);
float dist = (result.cols / 2) - ((result.rows / point_height) - b) / a;
//cout << dist << endl;
if (min_distance_left > dist && dist > 0) {
min_distance_left = dist;
}
//cout << min_distance_left << endl;
fprintf(files, "line: (%f,%f) \n", dist, min_distance_left);
// point of intersection of the line with first row
Point pt1(int(rho / cos(theta)), 0);
// point of intersection of the line with last row
Point pt2(int((rho - result.rows*sin(theta)) / cos(theta)), result.rows);
// draw a white line
line(result, pt1, pt2, Scalar(255), 8);
line(hough, pt1, pt2, Scalar(255), 8);
//}
//std::cout << "line: (" << rho << "," << theta << ")\n";
fprintf(files, "line: (%f,%f) \n", rho, theta);
++begin;
}
begin = 0;
float min_distance_right = float(result.cols) / 2;
while (begin < lines_right.size()) {
float rho = lines_right[begin][0]; // first element is distance rho
float theta = lines_right[begin][1]; // second element is angle theta
float a = -(cos(theta) / sin(theta));
float b = rho / sin(theta);
float dist = (0.5f - cut_off)*contours1.cols + ((result.rows / point_height) - b) / a;
//cout << dist << endl;
if (min_distance_right > dist && dist > 0) {
min_distance_right = dist;
}
//cout << min_distance_right << endl;
fprintf(files, "line: (%f,%f) \n", dist, min_distance_right);
//if (theta < 30.*PI / 180. || theta > 150.*PI / 180.) { // filter theta angle to find lines with theta between 30 and 150 degrees (mostly vertical)
// point of intersection of the line with first row
Point pt1(int(rho / cos(theta) + contours1.cols*(1 - cut_off)), 0);
// point of intersection of the line with last row
Point pt2(int((rho - result.rows*sin(theta)) / cos(theta) + contours1.cols*(1 - cut_off)), result.rows);
// draw a white line
line(result, pt1, pt2, Scalar(255), 8);
line(hough, pt1, pt2, Scalar(255), 8);
//}
//std::cout << "line: (" << rho << "," << theta << ")\n";
fprintf(files, "line: (%f,%f) \n", rho, theta);
++begin;
}
Point x1(result.cols / 2, 0);
Point x2(result.cols / 2, result.rows);
Point midle;
line(result, x1, x2, Scalar(255), 8);
x1 = { int((result.cols / 2) - min_distance_left),result.rows / point_height };
x2 = { int((result.cols / 2) + min_distance_right),result.rows / point_height };
midle = (x1 + x2) / 2;
circle(result, midle, 10, Scalar(0, 0, 255), -1);
line(result, x1, x2, Scalar(255), 8);
value = midle.x - (result.cols / 2);
mtx.lock();
result.copyTo(imgResult);
imgThresholded.copyTo(imgThresh);
mtx.unlock();
//this->show(1);
return value;
}
int ImageProccessing::start(string ip, unsigned short port)
{
//test
sf::UdpSocket socket;
socket.setBlocking(false);
sf::Packet packet;
sf::Int16 value = 0;
packet << value;
sf::IpAddress recipient = ip;
VideoCapture cap(0);
//VideoCapture cap("http://"+ip+":8080/stream/video.mjpeg"); //capture the video from web cam
if (!cap.isOpened()) // if not success, exit program
{
cout << "Cannot open the web cam" << endl;
system("pause");
return -1;
}
//this->setup();
Mat imgOriginal;
while (true) {
bool bSuccess = cap.read(imgOriginal); // read a new frame from video
if (!bSuccess) //if not success, break loop
{
cout << "Cannot read a frame from video stream" << endl;
break;
}
//wysylanie
this->update(imgOriginal);
this->tresh();
if (this->zeros(0.001f)) {
value = 1000;
//this->show(0);
}
else {
value = this->doProccessing();
}
packet.clear();
packet << value;
if (socket.send(packet, recipient, port) != sf::Socket::Done)
{
std::cout << "Some error" << std::endl;
return 12;
}
//koniec wysylania
//waitKey(0);
if (waitKey(10) == 27) //wait for 'esc' key press for 30ms. If 'esc' key is pressed, break loop
{
value = 1000;
packet.clear();
packet << value;
if (socket.send(packet, recipient, port) != sf::Socket::Done)
{
std::cout << "Some error" << std::endl;
return 12;
}
cout << "esc key is pressed by user" << endl;
break;
return 1;
}
}
isStarted = true;
}
I am new in OpenCV world and neural networks but I have some coding experience in C++/Java.
I created my first ANN MLP and learned it the XOR:
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/ml/ml.hpp>
#include <iostream>
#include <iomanip>
using namespace cv;
using namespace ml;
using namespace std;
void print(Mat& mat, int prec)
{
for (int i = 0; i<mat.size().height; i++)
{
cout << "[";
for (int j = 0; j<mat.size().width; j++)
{
cout << fixed << setw(2) << setprecision(prec) << mat.at<float>(i, j);
if (j != mat.size().width - 1)
cout << ", ";
else
cout << "]" << endl;
}
}
}
int main()
{
const int hiddenLayerSize = 4;
float inputTrainingDataArray[4][2] = {
{ 0.0, 0.0 },
{ 0.0, 1.0 },
{ 1.0, 0.0 },
{ 1.0, 1.0 }
};
Mat inputTrainingData = Mat(4, 2, CV_32F, inputTrainingDataArray);
float outputTrainingDataArray[4][1] = {
{ 0.0 },
{ 1.0 },
{ 1.0 },
{ 0.0 }
};
Mat outputTrainingData = Mat(4, 1, CV_32F, outputTrainingDataArray);
Ptr<ANN_MLP> mlp = ANN_MLP::create();
Mat layersSize = Mat(3, 1, CV_16U);
layersSize.row(0) = Scalar(inputTrainingData.cols);
layersSize.row(1) = Scalar(hiddenLayerSize);
layersSize.row(2) = Scalar(outputTrainingData.cols);
mlp->setLayerSizes(layersSize);
mlp->setActivationFunction(ANN_MLP::ActivationFunctions::SIGMOID_SYM);
TermCriteria termCrit = TermCriteria(
TermCriteria::Type::COUNT + TermCriteria::Type::EPS,
100000000,
0.000000000000000001
);
mlp->setTermCriteria(termCrit);
mlp->setTrainMethod(ANN_MLP::TrainingMethods::BACKPROP);
Ptr<TrainData> trainingData = TrainData::create(
inputTrainingData,
SampleTypes::ROW_SAMPLE,
outputTrainingData
);
mlp->train(trainingData
/*, ANN_MLP::TrainFlags::UPDATE_WEIGHTS
+ ANN_MLP::TrainFlags::NO_INPUT_SCALE
+ ANN_MLP::TrainFlags::NO_OUTPUT_SCALE*/
);
for (int i = 0; i < inputTrainingData.rows; i++) {
Mat sample = Mat(1, inputTrainingData.cols, CV_32F, inputTrainingDataArray[i]);
Mat result;
mlp->predict(sample, result);
cout << sample << " -> ";// << result << endl;
print(result, 0);
cout << endl;
}
return 0;
}
It works very well for this simple problem, I also learn this network the 1-10 to binary conversion.
But i need to use MLP for simple image classification - road signs. I write the code for loading training images and preparing matrix for learning but I'm not able to train the network - it "learn" in one second even with 1 000 000 iterations! And it produce garbage results, the same for all inputs!
Here are my test images and the source code:
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/ml/ml.hpp>
#include <iostream>
#include <chrono>
#include <memory>
#include <iomanip>
#include <climits>
#include <Windows.h>
using namespace cv;
using namespace ml;
using namespace std;
using namespace chrono;
const int WIDTH_SIZE = 50;
const int HEIGHT_SIZE = (int)(WIDTH_SIZE * sqrt(3)) / 2;
const int IMAGE_DATA_SIZE = WIDTH_SIZE * HEIGHT_SIZE;
void print(Mat& mat, int prec)
{
for (int i = 0; i<mat.size().height; i++)
{
cout << "[ ";
for (int j = 0; j<mat.size().width; j++)
{
cout << fixed << setw(2) << setprecision(prec) << mat.at<float>(i, j);
if (j != mat.size().width - 1)
cout << ", ";
else
cout << " ]" << endl;
}
}
}
bool loadImage(string imagePath, Mat& outputImage)
{
// load image in grayscale
Mat image = imread(imagePath, IMREAD_GRAYSCALE);
Mat temp;
// check for invalid input
if (image.empty()) {
cout << "Could not open or find the image" << std::endl;
return false;
}
// resize the image
Size size(WIDTH_SIZE, HEIGHT_SIZE);
resize(image, temp, size, 0, 0, CV_INTER_AREA);
// convert to float 1-channel
temp.convertTo(outputImage, CV_32FC1, 1.0/255.0);
return true;
}
vector<string> getFilesNamesInFolder(string folder)
{
vector<string> names;
char search_path[200];
sprintf(search_path, "%s/*.*", folder.c_str());
WIN32_FIND_DATA fd;
HANDLE hFind = ::FindFirstFile(search_path, &fd);
if (hFind != INVALID_HANDLE_VALUE) {
do {
// read all (real) files in current folder
// , delete '!' read other 2 default folder . and ..
if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
names.push_back(fd.cFileName);
}
} while (::FindNextFile(hFind, &fd));
::FindClose(hFind);
}
return names;
}
class Sign {
public:
enum class Category { A = 'A', B = 'B', C = 'C', D = 'D' };
Mat image;
Category category;
int number;
Sign(Mat& image, string name) :image(image) {
category = static_cast<Category>(name.at(0));
number = stoi(name.substr(2, name.length()));
};
};
vector<Sign> loadSignsFromFolder(String folderName) {
vector<Sign> roadSigns;
for (string fileName : getFilesNamesInFolder(folderName)) {
Mat image;
loadImage(folderName + fileName, image);
roadSigns.emplace_back(image, fileName.substr(0, (fileName.length() - 4))); //cut .png
}
return roadSigns;
}
void showSignsInWindows(vector<Sign> roadSigns) {
for (Sign sign : roadSigns) {
String windowName = "Sign " + to_string(sign.number);
namedWindow(windowName, WINDOW_AUTOSIZE);
imshow(windowName, sign.image);
}
waitKey(0);
}
Mat getInputDataFromSignsVector(vector<Sign> roadSigns) {
Mat roadSignsImageData;
for (Sign sign : roadSigns) {
Mat signImageDataInOneRow = sign.image.reshape(0, 1);
roadSignsImageData.push_back(signImageDataInOneRow);
}
return roadSignsImageData;
}
Mat getOutputDataFromSignsVector(vector<Sign> roadSigns) {
int signsCount = (int) roadSigns.size();
int signsVectorSize = signsCount + 1;
Mat roadSignsData(0, signsVectorSize, CV_32FC1);
int i = 1;
for (Sign sign : roadSigns) {
vector<float> outputTraningVector(signsVectorSize);
fill(outputTraningVector.begin(), outputTraningVector.end(), -1.0);
outputTraningVector[i++] = 1.0;
Mat tempMatrix(outputTraningVector, false);
roadSignsData.push_back(tempMatrix.reshape(0, 1));
}
return roadSignsData;
}
int main(int argc, char* argv[])
{
if (argc != 2) {
cout << " Usage: display_image ImageToLoadAndDisplay" << endl;
return -1;
}
const int hiddenLayerSize = 500;
vector<Sign> roadSigns = loadSignsFromFolder("../../../Znaki/A/");
Mat inputTrainingData = getInputDataFromSignsVector(roadSigns);
Mat outputTrainingData = getOutputDataFromSignsVector(roadSigns);
Ptr<ANN_MLP> mlp = ANN_MLP::create();
Mat layersSize = Mat(3, 1, CV_16U);
layersSize.row(0) = Scalar(inputTrainingData.cols);
layersSize.row(1) = Scalar(hiddenLayerSize);
layersSize.row(2) = Scalar(outputTrainingData.cols);
mlp->setLayerSizes(layersSize);
mlp->setActivationFunction(ANN_MLP::ActivationFunctions::SIGMOID_SYM, 1.0, 1.0);
mlp->setTrainMethod(ANN_MLP::TrainingMethods::BACKPROP, 0.05, 0.05);
//mlp->setTrainMethod(ANN_MLP::TrainingMethods::RPROP);
TermCriteria termCrit = TermCriteria(
TermCriteria::Type::MAX_ITER //| TermCriteria::Type::EPS,
,100 //(int) INT_MAX
,0.000001
);
mlp->setTermCriteria(termCrit);
Ptr<TrainData> trainingData = TrainData::create(
inputTrainingData,
SampleTypes::ROW_SAMPLE,
outputTrainingData
);
auto start = system_clock::now();
mlp->train(trainingData
//, //ANN_MLP::TrainFlags::UPDATE_WEIGHTS
, ANN_MLP::TrainFlags::NO_INPUT_SCALE
+ ANN_MLP::TrainFlags::NO_OUTPUT_SCALE
);
auto duration = duration_cast<milliseconds> (system_clock::now() - start);
cout << "Training time: " << duration.count() << "ms" << endl;
for (int i = 0; i < inputTrainingData.rows; i++) {
Mat result;
//mlp->predict(inputTrainingData.row(i), result);
mlp->predict(roadSigns[i].image.reshape(0, 1), result);
//cout << result << endl;
print(result, 2);
}
//showSignsInWindows(roadSigns);
return 0;
}
What is wrong in this code, that XOR works but images not? I cheked the input and output matrix and they're correct... could somebody also explain me when to/shoud I use the ANN_MLP::TrainFlags::NO_INPUT_SCALE and ANN_MLP::TrainFlags::NO_OUTPUT_SCALE or what values of setActivationFunction and setTrainMethod parameters should I use?
Thanks!
There was a problem in backprop weight scale parameter - it was too big and the ANN couldn't learn more difficult things.
I changed the line to mlp->setTrainMethod(ANN_MLP::TrainingMethods::BACKPROP, 0.0001); and the hidden layer size to 100 (to speed up the learning) - now it's working!
i am trying to use the code given in the tutorial but it is not working. i am sure all the dependencies are there and the program is compiling but it giving me some errors related that some functions can not be found.
here is the code:
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/face.hpp"
#include <iostream>
#include <fstream>
#include <sstream>
using namespace cv;
using namespace std;
static Mat norm_0_255(InputArray _src){
Mat src = _src.getMat();
Mat dst;
switch(src.channels()){
case 1:
cv::normalize(_src, dst, 0, 255, NORM_MINMAX, CV_8UC1);
break;
case 3:
cv::normalize(_src, dst, 0, 255, NORM_MINMAX, CV_8UC3);
break;
default:
src.copyTo(dst);
break;
}
return dst;
}
static void read_csv(const string& filename, vector<Mat>& images, vector<int>& labels, char separator = ';'){
std::ifstream file(filename.c_str(), ifstream::in);
if(!file){
string error_message = "No valid input file was given, please check the given filename.";
CV_Error(CV_StsBadArg, error_message);
}
string line, path, classlabel;
while(getline(file, line)){
stringstream liness(line);
getline(liness, path, separator);
getline(liness, classlabel);
if(!path.empty() && !classlabel.empty()){
images.push_back(imread(path, 0));
labels.push_back(atoi(classlabel.c_str()));
}
}
}
int main(int argc, const char *argv[]){
if(argc < 2){
cout << "usage: " << argv[0] << " <csv.ext> <output_folder> " << endl;
exit(0);
}
string output_folder = ".";
if(argc == 3){
output_folder = string(argv[2]);
}
string fn_csv = string(argv[1]);
vector<Mat> images;
vector<int> labels;
try{
read_csv(fn_csv, images, labels);
}catch(cv::Exception& e){
cerr << "Error opening file \"" << fn_csv << "\". Reason: " << e.msg << endl;
exit(1);
}
if(images.size() <= 1){
string error_message = "This demo needs at least 2 images to work. please add more images to your data set!";
CV_Error(CV_StsError, error_message);
}
int height = images[0].rows;
Mat testSample = images[images.size() - 1];
int testLabel = labels[labels.size() - 1];
images.pop_back();
labels.pop_back();
Ptr<cv::face::FaceRecognizer> model = cv::face::createEigenFaceRecognizer();
model->train(images, labels);
int predictedLabel = model->predict(testSample);
string result_message = format("Predicted class = %d / Actual class = %d ", predictedLabel, testLabel);
cout << result_message << endl;
Mat eigenvalues = model->getMat("eigenvalues");
Mat W = model->getMat("eigenvectors");
Mat mean = model->getMat("mean");
if(argc == 2){
imshow("mean", norm_0_255(mean.reshape(1, images[0].rows)));
}else{
imwrite(format("%s/mean.png", output_folder.c_str()), norm_0_255(mean.reshape(1, images[0].rows)));
}
// Display or save the Eigenfaces:
for (int i = 0; i < min(10, W.cols); i++) {
string msg = format("Eigenvalue #%d = %.5f", i, eigenvalues.at<double>(i));
cout << msg << endl;
// get eigenvector #i
Mat ev = W.col(i).clone();
// Reshape to original size & normalize to [0...255] for imshow.
Mat grayscale = norm_0_255(ev.reshape(1, height));
// Show the image & apply a Jet colormap for better sensing.
Mat cgrayscale;
applyColorMap(grayscale, cgrayscale, COLORMAP_JET);
// Display or save:
if(argc == 2) {
imshow(format("eigenface_%d", i), cgrayscale);
} else {
imwrite(format("%s/eigenface_%d.png", output_folder.c_str(), i), norm_0_255(cgrayscale));
}
}
// Display or save the image reconstruction at some predefined steps:
for(int num_components = min(W.cols, 10); num_components < min(W.cols, 300); num_components+=15) {
// slice the eigenvectors from the model
Mat evs = Mat(W, Range::all(), Range(0, num_components));
Mat projection = subspaceProject(evs, mean, images[0].reshape(1,1));
Mat reconstruction = subspaceReconstruct(evs, mean, projection);
// Normalize the result:
reconstruction = norm_0_255(reconstruction.reshape(1, images[0].rows));
// Display or save:
if(argc == 2) {
imshow(format("eigenface_reconstruction_%d", num_components), reconstruction);
} else {
imwrite(format("%s/eigenface_reconstruction_%d.png", output_folder.c_str(), num_components), reconstruction);
}
}
// Display if we are not writing to an output folder:
if(argc == 2) {
waitKey(0);
}
return 0;
}
CMakeLists.txt file:
cmake_minimum_required(VERSION 2.8)
project(faceReco)
find_package(OpenCV REQUIRED)
add_executable(faceReco faceReco.cpp)
target_link_libraries(faceReco ${OpenCV_LIBS})
Errors:
/home/abdulaziz/workspace/OpenCV_Projects/FaceReco/faceReco.cpp: In function ‘int main(int, const char**)’:
/home/abdulaziz/workspace/OpenCV_Projects/FaceReco/faceReco.cpp:110:27: error: ‘class cv::face::FaceRecognizer’ has no member named ‘getMat’
Mat eigenvalues = model->getMat("eigenvalues");
^
/home/abdulaziz/workspace/OpenCV_Projects/FaceReco/faceReco.cpp:111:17: error: ‘class cv::face::FaceRecognizer’ has no member named ‘getMat’
Mat W = model->getMat("eigenvectors");
^
/home/abdulaziz/workspace/OpenCV_Projects/FaceReco/faceReco.cpp:112:20: error: ‘class cv::face::FaceRecognizer’ has no member named ‘getMat’
Mat mean = model->getMat("mean");
^
/home/abdulaziz/workspace/OpenCV_Projects/FaceReco/faceReco.cpp:130:46: error: ‘COLORMAP_JET’ was not declared in this scope
applyColorMap(grayscale, cgrayscale, COLORMAP_JET);
^
/home/abdulaziz/workspace/OpenCV_Projects/FaceReco/faceReco.cpp:130:58: error: ‘applyColorMap’ was not declared in this scope
applyColorMap(grayscale, cgrayscale, COLORMAP_JET);
^
/home/abdulaziz/workspace/OpenCV_Projects/FaceReco/faceReco.cpp:143:75: error: ‘subspaceProject’ was not declared in this scope
Mat projection = subspaceProject(evs, mean, images[0].reshape(1,1));
^
/home/abdulaziz/workspace/OpenCV_Projects/FaceReco/faceReco.cpp:144:71: error: ‘subspaceReconstruct’ was not declared in this scope
Mat reconstruction = subspaceReconstruct(evs, mean, projection);
^
rmap_utils.h
#ifndef UTILS_RANGE_MAP_H
#define UTILS_RANGE_MAP_H
#include <stdlib.h>
#include <string>
#include <stdio.h>
#include <vector>
#include <sstream>
#include <fstream>
#include <iostream>
#include "opencv2\opencv.hpp"
class rmap_utils
{
public:
rmap_utils::rmap_utils(){}
rmap_utils::~rmap_utils(){}
int loadRmap(const std::string &path, float *& xMap, float *& yMap, float *& zMap, unsigned char *&rgbMap, int &height, int &width);
cv::Mat visualize_depth_image(float *img, int width, int height, bool visualize, std::string wName = "rangeMap");
cv::Mat visualize_rgb_image(unsigned char *img, int width, int height, bool visualize, std::string wName = "rangeMap");
cv::Mat visualize_normalized_rgb_image(float *img, int width, int height, bool visualize, std::string wName = "rangeMap");
float compute_rangeMap_resolution(float *xMap, float *yMap, float *zMap, int width, int height);
};
#endif
rmap_utils.cpp
#include "rmap_utils.h"
void Tokenize(const std::string &line, std::vector<std::string> &tokens, const std::string &delimiters = " ", const bool skipEmptyCells = true, const int maxNumTokens = std::numeric_limits<int>::max())
{
tokens.clear();
int nTokens = 0;
std::string::size_type pos = 0;
std::string::size_type lastPos = 0;
if(skipEmptyCells)
{
// Skip delimiters at beginning.
lastPos = line.find_first_not_of(delimiters, 0);
// Find first "non-delimiter".
pos = line.find_first_of(delimiters, lastPos);
while ( (std::string::npos != pos || std::string::npos != lastPos) && (nTokens < maxNumTokens) )
{
// Found a token, add it to the vector.
tokens.push_back(line.substr(lastPos, pos - lastPos));
nTokens++;
// Skip delimiters
lastPos = line.find_first_not_of(delimiters, pos);
// Find next "non-delimiter"
pos = line.find_first_of(delimiters, lastPos);
}
}
else
{
while ( (std::string::npos != pos) && (nTokens < maxNumTokens) )
{
pos = line.find_first_of(delimiters, lastPos);
tokens.push_back(line.substr(lastPos, pos - lastPos));
nTokens++;
lastPos = pos+1;
}
}
}
template <typename T> void Read_Array(std::ifstream &filev, T* &aData, unsigned long int &nData, const bool binaryFile = true)
{
if (!filev.is_open() )
{
std::cout << "ERROR (Read_Array): file is not open";
getchar();
exit(-1);
}
if(binaryFile)
{
//read number of elements
filev.read((char*)&nData, sizeof(nData) );
aData = new T[nData];
//read data
filev.read((char*)aData, sizeof(T)*nData );
if(filev.gcount() != (sizeof(T)*nData) )
{
std::cout << "ERROR (Read_Array): filev.gcount() != (sizeof(T)*nData) " << filev.gcount() << " " << (sizeof(T)*nData) << std::endl;
std::cout << "Are you sure you opened the file in binary mode?";
getchar();
exit(-1);
}
if(!filev.good())
{
std::cout << "ERROR (Read_Array): !filev.good() [eof fail bad] [" << filev.eof() << " " << filev.fail() << " " << filev.bad() << "]" << std::endl;
std::cout << "Are you sure you opened the file in binary mode?";
getchar();
exit(-1);
}
}
else
{
//read number of elements
std::string line;
std::getline(filev, line);
filev >> nData;
aData = new T[nData];
//read data
T* ptrData = aData;
for(unsigned long int da=0; da<nData; da++)
{
filev >> *ptrData;
ptrData++;
}
std::getline(filev, line);
if(!filev.good())
{
std::cout << "ERROR (Read_Array): !filev.good() [eof fail bad] [" << filev.eof() << " " << filev.fail() << " " << filev.bad() << "]" << std::endl;
getchar();
exit(-1);
}
}
}
template <typename T> void Read_Vector(std::ifstream &filev, std::vector<T> &vData, const bool binaryFile = true)
{
if (!filev.is_open() )
{
std::cout << "ERROR (Read_Vector): file is not open";
getchar();
exit(-1);
}
unsigned long int nData = 0;
if(binaryFile)
{
//read number of elements
filev.read((char*)&nData, sizeof(nData) );
vData.resize((size_t)nData);
//read data
filev.read((char*)(&vData[0]), sizeof(T)*nData );
if(filev.gcount() != (sizeof(T)*nData) )
{
std::cout << "ERROR (Read_Vector): filev.gcount() != (sizeof(T)*nData) " << filev.gcount() << " " << (sizeof(T)*nData) << std::endl;
std::cout << "Are you sure you opened the file in binary mode?";
getchar();
exit(-1);
}
if(!filev.good())
{
std::cout << "ERROR (Read_Vector): !filev.good() [eof fail bad] [" << filev.eof() << " " << filev.fail() << " " << filev.bad() << "]" << std::endl;
std::cout << "Are you sure you opened the file in binary mode?";
getchar();
exit(-1);
}
}
else
{
//read number of elements
std::string line;
std::getline(filev, line);
filev >> nData;
vData.resize((size_t)nData);
//read data
T* ptrData = &vData[0];
for(unsigned long int da=0; da<nData; da++)
{
filev >> (*ptrData);
ptrData++;
}
std::getline(filev, line);
if(!filev.good())
{
std::cout << "ERROR (Read_Vector): !filev.good() [eof fail bad] [" << filev.eof() << " " << filev.fail() << " " << filev.bad() << "]" << std::endl;
getchar();
exit(-1);
}
}
}
template<typename T> T LexicalCast(const std::string& s)
{
std::stringstream ss(s);
T result;
if ((ss >> result).fail() || !(ss >> std::ws).eof())
{
//throw std::bad_cast();
std::cout << "ERROR:Impossible to cast " << s;
getchar();
exit(-1);
}
return result;
}
//passi i puntatori vuoti e lui elaborando li riempe per come ti servono
int loadRmap(const std::string &path, float *& xMap, float *& yMap, float *& zMap, unsigned char *&rgbMap, int &height, int &width)
{
bool binaryFile = true;
std::ifstream in(path.c_str(), std::ios::binary|std::ios::in);
if(!in.is_open())
{
std::cout << "ERROR (RangeMap::Load_RMap): Problems opening file";
getchar();
exit(-1);
}
std::string line;
std::vector<std::string> tokens;
int nValidPoints = 0;
bool texture = false;
int nChannels = 1;
double resolution;
//read header
while (!in.eof())
{
getline (in, line);
// Ignore empty lines
if (line == "")
continue;
// Tokenize the line
Tokenize(line, tokens, "\t\r " );
// first line
if (tokens[0] == "RMap")
continue;
// version
if (tokens[0] == "version")
{
continue;
}
// height
if (tokens[0] == "height")
{
height = LexicalCast<int>(tokens[1]);
continue;
}
// width
if (tokens[0] == "width")
{
width = LexicalCast<int>(tokens[1]);
continue;
}
// nValidPoints
if (tokens[0] == "nValidPoints")
{
nValidPoints = LexicalCast<int>(tokens[1]);
continue;
}
// resolution
if (tokens[0] == "resolution")
{
resolution = LexicalCast<double>(tokens[1]);
continue;
}
// texture
if (tokens[0] == "texture")
{
texture = true;
if (tokens[1] == "GrayScale")
{
nChannels = 1;
}
else if (tokens[1] == "BGR")
{
nChannels = 3;
}
else
{
std::cout << "ERROR (RangeMap::Load_RMap): tokens[1] != \"GrayScale\" and tokens[1] != \"BGR\" ";
getchar();
exit(-1);
}
continue;
}
// end_header
if (tokens[0] == "headerEnd")
{
break;
}
}
if(in.eof())
{
in.close();
std::cout << "ERROR (RangeMap::Load_RMap): end_header tag not reached";
getchar();
exit(-1);
}
//read valid point map
bool* validMap = NULL;
unsigned long int nTotalPoints = 0;
Read_Array(in, validMap, nTotalPoints, binaryFile);
if(nTotalPoints != width*height)
{
in.close();
std::cout << "ERROR (RangeMap::Load_RMap): nTotalPoints != m_width*m_height " << nTotalPoints << " != " << width << " * " << height << std::endl;
getchar();
exit(-1);
}
//read maps
std::vector<float> xVals;
std::vector<float> yVals;
std::vector<float> zVals;
Read_Vector(in, xVals, binaryFile);
Read_Vector(in, yVals, binaryFile);
Read_Vector(in, zVals, binaryFile);
if(xVals.size() != nValidPoints)
{
in.close();
std::cout << "ERROR (RangeMap::Load_RMap): vMap_X.size() != nValidPoints " << xVals.size() << " != " << nValidPoints << std::endl;
getchar();
exit(-1);
}
if(yVals.size() != nValidPoints)
{
in.close();
std::cout << "ERROR (RangeMap::Load_RMap): vMap_Y.size() != nValidPoints " << yVals.size() << " != " << nValidPoints << std::endl;
getchar();
exit(-1);
}
if(zVals.size() != nValidPoints)
{
in.close();
std::cout << "ERROR (RangeMap::Load_RMap): vMap_Z.size() != nValidPoints " << zVals.size() << " != " << nValidPoints << std::endl;
getchar();
exit(-1);
}
//if(xMap)
//{
// delete[] xMap;
//}
xMap = new float[width*height];
/*if(yVals)
{
delete[] yVals;
}*/
yMap = new float[width*height];
/*if(zVals)
{
delete[] zVals;
}*/
zMap = new float[width*height];
float* ptrvMap_X = &xVals[0];
float* ptrvMap_Y = &yVals[0];
float* ptrvMap_Z = &zVals[0];
bool* ptrValidMap = validMap;
float* ptrXmap = xMap;
float* ptrYmap = yMap;
float* ptrZmap = zMap;
for(unsigned long int po=0; po<nTotalPoints; po++)
{
if(*ptrValidMap)
{
*ptrXmap = *(ptrvMap_X++);
*ptrYmap = *(ptrvMap_Y++);
*ptrZmap = *(ptrvMap_Z++);
}
else
{
*ptrZmap = std::numeric_limits<float>::quiet_NaN();
}
ptrXmap++;
ptrYmap++;
ptrZmap++;
ptrValidMap++;
}
delete[] validMap;
//read texture
if(texture)
{
IplImage* m_texture = cvCreateImage(cvSize(width, height), 8, nChannels);
rgbMap = new unsigned char[width*height*3];
in.read( (char*)(m_texture->imageData), height*m_texture->widthStep );
if(in.gcount() != height*m_texture->widthStep)
{
std::cout << "ERROR (RangeMap::Load_RMap): in.gcount() != m_height*m_texture->widthStep " << in.gcount() << " " << height*m_texture->widthStep;
getchar();
exit(-1);
}
if(!in.good())
{
std::cout << "ERROR (RangeMap::Load_RMap): !in.good() in reading m_texture [eof fail bad] [" << in.eof() << " " << in.fail() << " " << in.bad() << "]";
getchar();
exit(-1);
}
for (int j=0; j<height; j++)
{
for ( int i=0; i<width; i++)
{
if ( nChannels == 3)
{
rgbMap[ j*width*3+i*3 ] = ((unsigned char *)(m_texture->imageData))[ j * m_texture->widthStep + i*3];
rgbMap[ j*width*3+i*3 +1 ] = ((unsigned char *)(m_texture->imageData))[ j * m_texture->widthStep + i*3 +1];
rgbMap[ j*width*3+i*3 +2 ] = ((unsigned char *)(m_texture->imageData))[ j * m_texture->widthStep + i*3 +2];
}
else
{
rgbMap[ j*width*3+i*3+2 ] = ((unsigned char *)(m_texture->imageData))[ j * m_texture->widthStep + i];
rgbMap[ j*width*3+i*3+1 ] = ((unsigned char *)(m_texture->imageData))[ j * m_texture->widthStep + i];
rgbMap[ j*width*3+i*3 ] = ((unsigned char *)(m_texture->imageData))[ j * m_texture->widthStep + i];
}
}
}
/*cvNamedWindow("cicciux", 0);
cvShowImage("cicciux", m_texture);
cvWaitKey(0);*/
cvReleaseImage(&m_texture);
}
else
{
rgbMap = NULL;
}
in.close();
return nValidPoints;
}
cv::Mat visualize_depth_image(float *img, int width, int height, bool visualize, std::string wName)
{
cv::Mat mat(height, width, CV_8UC3);
float dmax = -1;
float dmin = std::numeric_limits<float>::max();
for ( int j=0; j<height; j++)
{
for ( int i=0; i<width; i++)
{
if ( img[j*width+i] == img[j*width+i] )
{
if ( img[j*width+i] > dmax )
dmax = img[j*width+i];
if (img[j*width+i]<dmin)
dmin = img[j*width+i];
}
}
}
for ( int j=0; j<height; j++)
{
for ( int i=0; i<width; i++)
{
if ( img[j*width+i] == img[j*width+i] )
{
unsigned char pixel = cv::saturate_cast<unsigned char>( ((img[j*width+i] - dmin)* 255.0f) / (dmax-dmin) ) ;
mat.at<cv::Vec3b>(j,i)[0] = pixel;
mat.at<cv::Vec3b>(j,i)[1] = pixel;
mat.at<cv::Vec3b>(j,i)[2] = pixel;
}
else
{
mat.at<cv::Vec3b>(j,i)[0] = 0;
mat.at<cv::Vec3b>(j,i)[1] = 0;
mat.at<cv::Vec3b>(j,i)[2] = 255;
}
}
}
if ( visualize)
{
cv::imshow(wName, mat);
cv::waitKey(0);
}
return mat;
}
cv::Mat visualize_rgb_image(unsigned char *img, int width, int height, bool visualize, std::string wName)
{
cv::Mat mat(height, width, CV_8UC3);
for ( int j=0; j<height; j++)
{
for ( int i=0; i<width; i++)
{
for ( int c=0; c<3; c++)
{
mat.at<cv::Vec3b>(j,i)[c] = img[j*width*3 + i*3 + c];
}
}
}
if ( visualize )
{
cv::imshow(wName, mat);
cv::waitKey(0);
}
return mat;
}
cv::Mat visualize_normalized_rgb_image(float *img, int width, int height, bool visualize, std::string wName)
{
cv::Mat mat(height, width, CV_8UC3);
for ( int j=0; j<height; j++)
{
for ( int i=0; i<width; i++)
{
for ( int c=0; c<3; c++)
{
mat.at<cv::Vec3b>(j,i)[c] = static_cast<unsigned char>(std::floor(img[j*width*3 + i*3 + c] * 255));
}
}
}
if ( visualize)
{
cv::imshow(wName, mat);
cv::waitKey(0);
}
return mat;
}
float compute_rangeMap_resolution(float *xMap, float *yMap, float *zMap, int width, int height)
{
float res = 0.0f;
int nCount = 0;
for ( int j=0; j<height-1; j++)
{
for ( int i=0; i<width-1; i++)
{
if ( zMap[j*width+i] == zMap[j*width+i] )
{
if ( zMap[j*width+i+1] == zMap[j*width+i+1] )
{
nCount ++ ;
res += (zMap[j*width+i]-zMap[j*width+i+1])*(zMap[j*width+i]-zMap[j*width+i+1]) + (yMap[j*width+i]-yMap[j*width+i+1])*(yMap[j*width+i]-yMap[j*width+i+1]) + (xMap[j*width+i]-xMap[j*width+i+1])*(xMap[j*width+i]-xMap[j*width+i+1]);
}
if ( zMap[(j+1)*width+i] == zMap[(j+1)*width+i] )
{
nCount ++ ;
res += (zMap[j*width+i]-zMap[(j+1)*width+i])*(zMap[j*width+i]-zMap[(j+1)*width+i]) + (yMap[j*width+i]-yMap[(j+1)*width+i])*(yMap[j*width+i]-yMap[(j+1)*width+i]) + (xMap[j*width+i]-xMap[(j+1)*width+i])*(xMap[j*width+i]-xMap[(j+1)*width+i]);
}
}
}
}
res /= nCount;
res = sqrt(res);
return res;
}
Error List:
error LNK2019: unresolved external symbol "public: int __cdecl rmap_utils::loadRmap(class std::basic_string,class std::allocator > const &,float * &,float * &,float * &,unsigned char * &,int &,int &)" (?loadRmap#rmap_utils##QEAAHAEBV?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std##AEAPEAM11AEAPEAEAEAH3#Z) referenced in function main
In rmap_utils.cpp replace
int loadRmap(const std::string &path, float *& xMap, float *& yMap, float *& zMap, unsigned char *&rgbMap, int &height, int &width)
With:
int rmap_utils::loadRmap(const std::string &path, float *& xMap, float *& yMap, float *& zMap, unsigned char *&rgbMap, int &height, int &width)
I am using Hog+SVM in opencv for detecting cars in Video avi file. I am using car.xml model file.
I am not getting good results when I used LatentSvmDetetction for detecting cars
A Large number of false detections in frame.
It is very slow. It takes about 5 seconds to detect objects from a frame.
Please suggest me how to improve object detection time.
My code is below:
#include <iostream>
#include "opencv2/objdetect/objdetect.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/contrib/contrib.hpp"
#if defined(WIN32) || defined(_WIN32)
#include <io.h>
#else
#include <dirent.h>
#endif
#ifdef HAVE_CVCONFIG_H
#include <cvconfig.h>
#endif
#ifdef HAVE_TBB
#include "tbb/task_scheduler_init.h"
#endif
using namespace std;
using namespace cv;
static void detectAndDrawObjects( Mat& frame, LatentSvmDetector& detector, const vector<Scalar>& colors, float overlapThreshold, int numThreads )
{
vector<LatentSvmDetector::ObjectDetection> detections;
TickMeter tm;
tm.start();
detector.detect( frame, detections, overlapThreshold, numThreads);
tm.stop();
cout << "Detection time = " << tm.getTimeSec() << " sec" << endl;
const vector<string> classNames = detector.getClassNames();
CV_Assert( colors.size() == classNames.size() );
for( size_t i = 0; i < detections.size(); i++ )
{
const LatentSvmDetector::ObjectDetection& od = detections[i];
rectangle( frame, od.rect, colors[od.classID], 3 );
putText( frame, classNames[od.classID], Point(od.rect.x+4,od.rect.y+13), FONT_HERSHEY_SIMPLEX, 0.55, colors[od.classID], 2 );
}
}
static void readDirectory( const string& directoryName, vector<string>& filenames, bool addDirectoryName=true )
{
filenames.clear();
#if defined(WIN32) | defined(_WIN32)
struct _finddata_t s_file;
string str = directoryName + "\\*.*";
intptr_t h_file = _findfirst( str.c_str(), &s_file );
if( h_file != static_cast<intptr_t>(-1.0) )
{
do
{
if( addDirectoryName )
filenames.push_back(directoryName + "\\" + s_file.name);
else
filenames.push_back((string)s_file.name);
}
while( _findnext( h_file, &s_file ) == 0 );
}
_findclose( h_file );
#else
DIR* dir = opendir( directoryName.c_str() );
if( dir != NULL )
{
struct dirent* dent;
while( (dent = readdir(dir)) != NULL )
{
if( addDirectoryName )
filenames.push_back( directoryName + "/" + string(dent->d_name) );
else
filenames.push_back( string(dent->d_name) );
}
closedir( dir );
}
#endif
sort( filenames.begin(), filenames.end() );
}
int main()
{
string frames_folder, models_folder;
float overlapThreshold = 0.2f;
int numThreads = -1;
models_folder = "D:\\Downloads\\models_VOC2007";
VideoCapture cap("D:\\images\\videos\\vid2.AVI"); // open the video file for reading
cvNamedWindow("MyVideo", CV_WINDOW_AUTOSIZE);
if ( !cap.isOpened() ) // if not success, exit program
{
cout << "Cannot open the video file" << endl;
return -1;
}
LatentSvmDetector detector( models_filenames );
if( detector.empty() )
{
cout << "Models cann't be loaded" << endl;
exit(-1);
}
vector<Scalar> colors;
generateColors( colors, detector.getClassNames().size() );
Mat frame;
while(1)
{
bool bSuccess = cap.read(frame);
if (!bSuccess) //if not success, break loop
{
cout << "Cannot read the frame from video file" << endl;
break;
}
detectAndDrawObjects( frame, detector, colors, overlapThreshold, numThreads );
imshow( "MyVideo", frame );
//imshow("video", frame); //show the frame in "MyVideo" window
if(waitKey(30) == 27) //wait for 'esc' key press for 30 ms. If 'esc' key is pressed, break loop
{
cout << "esc key is pressed by user" << endl;
break;
}
}
return 0;
}
I suggest you
to resize the frame to a size that 10x5 pixel is the smallest possible car in the frame;
to do a blur first; it is possible to get lots of false-positives because there is noise that generate edges that can be similar to the car;
I suppose that the detector is for side cars (I have not tested it) ant it will not detect cars rotated with more than 60 degrees and it is trained on some database that was not similar to your environment; so maybe it is better to train your own detector (car.xml).
HOG is based on edges and edges are very sensible to light and shadows. Try to preprocess (contrast enhancement) the frame before detecting the cars.