Files
openalpr-base/src/misc_utilities/prepcharsfortraining.cpp

225 lines
7.3 KiB
C++

/*
* 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 "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
#include <fstream>
#include <sys/stat.h>
#include "support/filesystem.h"
#include "../tclap/CmdLine.h"
using namespace std;
using namespace cv;
using namespace alpr;
// Takes a directory full of single char images, and plops them on a big tif files
// Also creates a box file so Tesseract can recognize it
int main( int argc, const char** argv )
{
string inDir;
int tile_width;
int tile_height;
TCLAP::CmdLine cmd("OpenAlpr OCR Training Prep Utility", ' ', "1.0.0");
TCLAP::UnlabeledValueArg<std::string> inputDirArg( "input_dir", "Folder containing individual character images", true, "", "input_dir_path" );
TCLAP::ValueArg<int> tileWidthArg("","tile_width","Width (in pixels) for each character tile. Default=50",false, 50 ,"tile_width_px");
TCLAP::ValueArg<int> tileHeightArg("","tile_height","Height (in pixels) for each character tile. Default=60",false, 60 ,"tile_height_px");
try
{
cmd.add( inputDirArg );
cmd.add( tileWidthArg );
cmd.add( tileHeightArg );
if (cmd.parse( argc, argv ) == false)
{
// Error occured while parsing. Exit now.
return 1;
}
inDir = inputDirArg.getValue();
tile_width = tileWidthArg.getValue();
tile_height = tileHeightArg.getValue();
}
catch (TCLAP::ArgException &e) // catch any exceptions
{
std::cerr << "error: " << e.error() << " for arg " << e.argId() << std::endl;
return 1;
}
if (DirectoryExists(inDir.c_str()) == false)
{
printf("Output dir does not exist\n");
return 0;
}
if (DirectoryExists(inDir.c_str()))
{
const int CHAR_PADDING_HORIZONTAL = 0;
const int CHAR_PADDING_VERTICAL = 0;
const int X_OFFSET = 5;
const int Y_OFFSET = 5;
const int PAGE_MARGIN_X = 70;
const int PAGE_MARGIN_Y = 70;
const int HORIZONTAL_RESOLUTION = 3500;
const int MAX_VERTICAL_RESOLUTION = 6000; // Maximum vertical size before chopping into additional pages.
const int TILE_WIDTH = tile_width;
const int TILE_HEIGHT = tile_height;
const int CHAR_HORIZ_OFFSET = 40;
const int CHAR_VERT_OFFSET = 48;
const int FIXED_CHAR_HEIGHT = 40; // RESIZE all characters to this height
vector<string> files = getFilesInDir(inDir.c_str());
sort( files.begin(), files.end(), stringCompare );
for (int i = 0; i< files.size(); i++)
{
if (hasEnding(files[i], ".png") || hasEnding(files[i], ".jpg"))
{
}
else
{
std::cerr << "Non-image file detected in this directory. This must be removed first" << std::endl;
return 1;
}
}
int tiles_per_row = ((float) (HORIZONTAL_RESOLUTION - (PAGE_MARGIN_X * 2))) / ((float) TILE_WIDTH);
int lines = files.size() / (tiles_per_row);
int vertical_resolution = (lines * TILE_HEIGHT) + (PAGE_MARGIN_Y * 3) ;
cout << tiles_per_row << " : " << vertical_resolution << endl;
Mat bigTif = Mat::zeros(Size(HORIZONTAL_RESOLUTION, vertical_resolution), CV_8U);
bitwise_not(bigTif, bigTif);
stringstream boxFileOut;
for (int i = 0; i< files.size(); i++)
{
int col = i % tiles_per_row;
int line = i / tiles_per_row;
int xPos = (col * TILE_WIDTH) + PAGE_MARGIN_X;
int yPos = (line * TILE_HEIGHT) + PAGE_MARGIN_Y;
if (hasEnding(files[i], ".png") || hasEnding(files[i], ".jpg"))
{
string fullpath = inDir + "/" + files[i];
cout << "Processing file: " << (i + 1) << " of " << files.size() << endl;
char charcode = files[i][0];
Mat characterImg = imread(fullpath);
Mat charImgCopy = Mat::zeros(Size(150, 150), characterImg.type());
bitwise_not(charImgCopy, charImgCopy);
characterImg.copyTo(charImgCopy(Rect(X_OFFSET, Y_OFFSET, characterImg.cols, characterImg.rows)));
cvtColor(charImgCopy, charImgCopy, CV_BGR2GRAY);
bitwise_not(charImgCopy, charImgCopy);
vector<vector<Point> > contours;
//imshow("copy", charImgCopy);
findContours(charImgCopy, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
float minHeightPercent = 0.35;
int minHeight = (int) (((float) characterImg.rows) * minHeightPercent);
vector<Rect> tallEnoughRects;
for (int c = 0; c < contours.size(); c++)
{
Rect tmpRect = boundingRect(contours[c]);
if (tmpRect.height > minHeight)
tallEnoughRects.push_back( tmpRect );
}
int xMin = 9999999, xMax = 0, yMin = 9999999, yMax = 0;
// Combine all the "tall enough" rectangles into one super rectangle
for (int r = 0; r < tallEnoughRects.size(); r++)
{
if (tallEnoughRects[r].x < xMin)
xMin = tallEnoughRects[r].x;
if (tallEnoughRects[r].y < yMin)
yMin = tallEnoughRects[r].y;
if (tallEnoughRects[r].x + tallEnoughRects[r].width > xMax)
xMax = tallEnoughRects[r].x + tallEnoughRects[r].width;
if (tallEnoughRects[r].y + tallEnoughRects[r].height > yMax)
yMax = tallEnoughRects[r].y + tallEnoughRects[r].height;
}
Rect tallestRect(xMin, yMin, xMax - xMin, yMax - yMin);
//cout << tallestRect.x << ":" << tallestRect.y << " -- " << tallestRect.width << ":" << tallestRect.height << endl;
Rect cropRect(0, tallestRect.y - Y_OFFSET, tallestRect.width, tallestRect.height);
//cout << "Cropped: " << cropRect.x << ":" << cropRect.y << " -- " << cropRect.width << ":" << cropRect.height << endl;
Mat cropped(characterImg, cropRect);
cvtColor(cropped, cropped, CV_BGR2GRAY);
Rect destinationRect(xPos + (CHAR_HORIZ_OFFSET - TILE_WIDTH), yPos + (CHAR_VERT_OFFSET - TILE_HEIGHT + (TILE_HEIGHT - tallestRect.height)), tallestRect.width, tallestRect.height);
//cout << "1" << endl;
cropped.copyTo(bigTif(destinationRect));
int x1 = destinationRect.x - CHAR_PADDING_HORIZONTAL;
int y1 = (vertical_resolution - destinationRect.y - destinationRect.height) - CHAR_PADDING_VERTICAL;
int x2 = (destinationRect.x + destinationRect.width) + CHAR_PADDING_HORIZONTAL;
int y2 = (vertical_resolution - destinationRect.y) + CHAR_PADDING_VERTICAL;
//0 70 5602 85 5636 0
boxFileOut << charcode << " " << x1 << " " << y1 << " ";
boxFileOut << x2 << " " << y2 ;
boxFileOut << " 0" << endl;
//rectangle(characterImg, tallestRect, Scalar(0, 255, 0));
//imshow("characterImg", cropped);
waitKey(2);
}
}
imwrite("combined.tif", bigTif);
ofstream boxFile("combined.box", std::ios::out);
boxFile << boxFileOut.str();
}
}