Added camera calibration utility

This commit is contained in:
Matt Hill
2015-05-15 06:54:02 -04:00
parent a804bdc3fc
commit e5aa1389e0
2 changed files with 407 additions and 0 deletions

View File

@@ -49,9 +49,22 @@ TARGET_LINK_LIBRARIES(openalpr-utils-tagplates
${OpenCV_LIBS}
)
ADD_EXECUTABLE( openalpr-utils-calibrate calibrate.cpp )
TARGET_LINK_LIBRARIES(openalpr-utils-calibrate
openalpr
support
${OpenCV_LIBS}
${Tesseract_LIBRARIES}
)
install (TARGETS openalpr-utils-calibrate DESTINATION bin)
install (TARGETS openalpr-utils-sortstate DESTINATION bin)
install (TARGETS openalpr-utils-classifychars DESTINATION bin)
install (TARGETS openalpr-utils-benchmark DESTINATION bin)
install (TARGETS openalpr-utils-prepcharsfortraining DESTINATION bin)
install (TARGETS openalpr-utils-tagplates DESTINATION bin)
install (TARGETS openalpr-utils-calibrate DESTINATION bin)

View File

@@ -0,0 +1,394 @@
/*
* Copyright (c) 2015 New Designs Unlimited, LLC
* Opensource Automated License Plate Recognition [http://www.openalpr.com]
*
* This file is part of OpenAlpr.
*
* OpenAlpr is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License
* version 3 as published by the Free Software Foundation
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <cstdlib>
#include <cstdio>
#include <iostream>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/calib3d/calib3d.hpp>
#include "support/filesystem.h"
#include "../tclap/CmdLine.h"
#include "prewarp.h"
#include <sstream>
using namespace std;
using namespace cv;
const int INSTRUCTIONS_HEIGHT = 32;
bool panning;
bool left_clicking;
Point left_click_start;
Point left_click_cur;
Point lastPos;
float w;
float h;
float panX = 0;
float panY = 0;
float rotationx = 0;
float rotationy = 0;
float rotationz = 0;
float stretchX = 1.0;
float dist = 1.0;
Mat imgOriginal;
Mat curWarpedImage;
alpr::Config config("us");
const string WINDOW_NAME = "Adjust OpenALPR Perspective";
string get_config()
{
stringstream output;
output << "planar," << std::fixed;
output << w << "," << h << ",";
output << rotationx << "," << rotationy << "," << rotationz << ",";
output << stretchX << "," << dist << ",";
output << panX << "," << panY;
return output.str();
}
void drawImage(Mat img)
{
config.prewarp = get_config();
alpr::PreWarp prewarp(&config);
if (!left_clicking)
{
curWarpedImage = prewarp.warpImage(img);
}
Mat imgWithInstructions(curWarpedImage.rows + INSTRUCTIONS_HEIGHT, curWarpedImage.cols, curWarpedImage.type());
curWarpedImage.copyTo(imgWithInstructions(Rect(0, INSTRUCTIONS_HEIGHT, curWarpedImage.cols, curWarpedImage.rows)));
if (left_clicking)
{
Point start = left_click_start;
Point end = left_click_cur;
start.y += INSTRUCTIONS_HEIGHT;
end.y += INSTRUCTIONS_HEIGHT;
rectangle(imgWithInstructions, start, end, Scalar(255,0,255), 2);
}
rectangle(imgWithInstructions, Point(0,0), Point(curWarpedImage.cols, INSTRUCTIONS_HEIGHT), Scalar(255,255,255), -1);
putText(imgWithInstructions, "Press 'o' to output config to console.",
Point(5,25), FONT_HERSHEY_DUPLEX, 1.0, Scalar(0,0,0));
imshow(WINDOW_NAME, imgWithInstructions);
}
void mouse_callback(int event, int x, int y, int flags, void* userdata)
{
y = y - INSTRUCTIONS_HEIGHT;
if (y < 0)
return;
if (event == EVENT_RBUTTONDOWN)
{
lastPos.x = x;
lastPos.y = y;
panning = true;
}
if (event == EVENT_RBUTTONUP)
{
panning = false;
drawImage(imgOriginal);
}
if (event == EVENT_MOUSEMOVE && panning)
{
int xdiff = x - lastPos.x;
int ydiff = y - lastPos.y;
panX -= xdiff;
panY -= ydiff;
lastPos.x = x;
lastPos.y = y;
// Reduce the computation by only doing it every 3rd pixel
if (x % 3 == 0 && y % 3 == 0)
{
drawImage(imgOriginal);
}
}
if (event == EVENT_LBUTTONDOWN)
{
left_click_start.x = x;
left_click_start.y = y;
left_clicking = true;
}
if (event == EVENT_LBUTTONUP)
{
left_clicking = false;
drawImage(imgOriginal);
}
if (event == EVENT_MOUSEMOVE && left_clicking)
{
left_click_cur.x = x;
float IDEAL_PLATE_RATIO = config.charWidthMM / config.charHeightMM;
float curWidth = left_click_cur.x - left_click_start.x;
left_click_cur.y = left_click_start.y + (IDEAL_PLATE_RATIO * curWidth);
// Reduce the computation by only doing it every 3rd pixel
if (x % 2 == 0 || y % 2 == 0)
{
drawImage(imgOriginal);
}
}
}
void ZChange(int pos, void* userdata)
{
rotationz = -((float)pos - 100) / 100.0;
drawImage(imgOriginal);
}
void XChange(int pos, void* userdata)
{
rotationx = -((float)pos - 100) / 20000.0;
drawImage(imgOriginal);
}
void YChange(int pos, void* userdata)
{
rotationy = ((float)pos - 100) / 20000.0;
drawImage(imgOriginal);
}
void DistChange(int pos, void* userdata)
{
dist = 1.0 - ((float)pos - 100) / 200.0;
drawImage(imgOriginal);
}
void StretchChange(int pos, void* userdata)
{
stretchX = 1.0 + ((float)pos - 100) / -200.0;
drawImage(imgOriginal);
}
int value;
void create_window()
{
namedWindow(WINDOW_NAME, CV_WINDOW_AUTOSIZE | CV_WINDOW_KEEPRATIO | CV_GUI_EXPANDED);
value = 100;
panX = 0;
panY = 0;
XChange(100, NULL);
YChange(100, NULL);
ZChange(100, NULL);
DistChange(100, NULL);
createTrackbar( "X", WINDOW_NAME, &value, 200, XChange);
createTrackbar( "Y", WINDOW_NAME, &value, 200, YChange);
createTrackbar( "Z", WINDOW_NAME, &value, 200, ZChange);
createTrackbar( "W", WINDOW_NAME, &value, 200, StretchChange);
createTrackbar( "D", WINDOW_NAME, &value, 200, DistChange);
setMouseCallback(WINDOW_NAME, mouse_callback, NULL);
}
/*
*
*/
int main(int argc, char** argv) {
string filename;
string country;
string config_path;
string translate_config;
int max_width;
int max_height;
TCLAP::CmdLine cmd("OpenAlpr Perspective Utility", ' ', "0.1");
TCLAP::UnlabeledValueArg<std::string> fileArg( "image_file", "Image containing license plates", true, "", "image_file_path" );
TCLAP::ValueArg<std::string> countryCodeArg("c","country","Country code to identify (either us for USA or eu for Europe). Default=us",false, "us" ,"country_code");
TCLAP::ValueArg<std::string> configFileArg("","config","Path to the openalpr.conf file",false, "" ,"config_file");
TCLAP::ValueArg<std::string> translateTestArg("t","test","Test an image using the provided translation config",false, "" ,"prewarp config");
TCLAP::ValueArg<int> maxWidthArg("w", "maxwidth", "Max Width used for displaying image in this utility. Default=1280",false, 1280 ,"max width");
TCLAP::ValueArg<int> maxHeightArg("", "maxheight", "Max Height used for displaying image in this utility. Default=1024",false, 1024 ,"max height");
try
{
cmd.add( configFileArg );
cmd.add( fileArg );
cmd.add( countryCodeArg );
cmd.add( translateTestArg );
cmd.add( maxWidthArg );
cmd.add( maxHeightArg );
if (cmd.parse( argc, argv ) == false)
{
// Error occured while parsing. Exit now.
return 1;
}
filename = fileArg.getValue();
country = countryCodeArg.getValue();
config_path = configFileArg.getValue();
translate_config = translateTestArg.getValue();
max_width = maxWidthArg.getValue();
max_height = maxHeightArg.getValue();
}
catch (TCLAP::ArgException &e) // catch any exceptions
{
std::cerr << "error: " << e.error() << " for arg " << e.argId() << std::endl;
return 1;
}
if (!alpr::fileExists(filename.c_str()))
{
cerr << "Could not find image file: " << filename << endl;
}
config = alpr::Config(country);
panning = false;
left_clicking = false;
imgOriginal = imread(filename);
if (imgOriginal.cols > max_width)
{
float aspect = max_width / ((float)imgOriginal.cols);
float y = ((float)imgOriginal.rows) * aspect;
resize(imgOriginal, imgOriginal, Size((int) max_width, (int) y));
}
if (imgOriginal.rows > max_height)
{
float aspect = max_height / ((float)imgOriginal.rows);
float x = ((float)imgOriginal.cols) * aspect;
resize(imgOriginal, imgOriginal, Size((int) x, (int) max_height));
}
w = imgOriginal.cols;
h = imgOriginal.rows;
create_window();
if (translate_config != "")
{
int first_comma = translate_config.find(",");
string name = translate_config.substr(0, first_comma);
stringstream ss(translate_config.substr(first_comma + 1, translate_config.length()));
ss >> w;
ss.ignore();
ss >> h;
ss.ignore();
ss >> rotationx;
ss.ignore(); // Ignore comma
ss >> rotationy;
ss.ignore(); // Ignore comma
ss >> rotationz;
ss.ignore(); // Ignore comma
ss >> stretchX;
ss.ignore(); // Ignore comma
ss >> dist;
ss.ignore(); // Ignore comma
ss >> panX;
ss.ignore(); // Ignore comma
ss >> panY;
}
float width_ratio = w / ((float)imgOriginal.cols);
float height_ratio = h / ((float)imgOriginal.rows);
w = imgOriginal.cols;
h = imgOriginal.rows;
rotationx *=width_ratio;
rotationy *=width_ratio;
panX /= width_ratio;
panY /= height_ratio;
drawImage(imgOriginal);
while (true)
{
char c = waitKey(15);
if (c == 'o')
{
cout << "prewarp = " << get_config() << endl;
}
}
cvDestroyAllWindows();
return 0;
}