mirror of
https://github.com/kerberos-io/openalpr-base.git
synced 2025-10-06 01:16:50 +08:00
Wrapped OpenALPR library in "alpr" namespace. Resolves issue #60.
This commit is contained in:
@@ -23,230 +23,234 @@ using namespace cv;
|
||||
using namespace std;
|
||||
|
||||
const float MIN_CONFIDENCE = 0.3;
|
||||
|
||||
|
||||
PlateLines::PlateLines(PipelineData* pipelineData)
|
||||
|
||||
namespace alpr
|
||||
{
|
||||
this->pipelineData = pipelineData;
|
||||
|
||||
this->debug = pipelineData->config->debugPlateLines;
|
||||
|
||||
if (debug)
|
||||
cout << "PlateLines constructor" << endl;
|
||||
}
|
||||
|
||||
PlateLines::~PlateLines()
|
||||
{
|
||||
}
|
||||
|
||||
void PlateLines::processImage(Mat inputImage, vector<TextLine> textLines, float sensitivity)
|
||||
{
|
||||
if (this->debug)
|
||||
cout << "PlateLines findLines" << endl;
|
||||
|
||||
timespec startTime;
|
||||
getTime(&startTime);
|
||||
|
||||
|
||||
// Ignore input images that are pure white or pure black
|
||||
Scalar avgPixelIntensity = mean(inputImage);
|
||||
if (avgPixelIntensity[0] == 255)
|
||||
return;
|
||||
else if (avgPixelIntensity[0] == 0)
|
||||
return;
|
||||
|
||||
// Do a bilateral filter to clean the noise but keep edges sharp
|
||||
Mat smoothed(inputImage.size(), inputImage.type());
|
||||
adaptiveBilateralFilter(inputImage, smoothed, Size(3,3), 45, 45);
|
||||
|
||||
|
||||
int morph_elem = 2;
|
||||
int morph_size = 2;
|
||||
Mat element = getStructuringElement( morph_elem, Size( 2*morph_size + 1, 2*morph_size+1 ), Point( morph_size, morph_size ) );
|
||||
|
||||
|
||||
Mat edges(inputImage.size(), inputImage.type());
|
||||
Canny(smoothed, edges, 66, 133);
|
||||
|
||||
// Create a mask that is dilated based on the detected characters
|
||||
|
||||
|
||||
Mat mask = Mat::zeros(inputImage.size(), CV_8U);
|
||||
|
||||
for (uint i = 0; i < textLines.size(); i++)
|
||||
PlateLines::PlateLines(PipelineData* pipelineData)
|
||||
{
|
||||
vector<vector<Point> > polygons;
|
||||
polygons.push_back(textLines[i].textArea);
|
||||
fillPoly(mask, polygons, Scalar(255,255,255));
|
||||
this->pipelineData = pipelineData;
|
||||
|
||||
this->debug = pipelineData->config->debugPlateLines;
|
||||
|
||||
if (debug)
|
||||
cout << "PlateLines constructor" << endl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
dilate(mask, mask, getStructuringElement( 1, Size( 1 + 1, 2*1+1 ), Point( 1, 1 ) ));
|
||||
bitwise_not(mask, mask);
|
||||
|
||||
// AND canny edges with the character mask
|
||||
bitwise_and(edges, mask, edges);
|
||||
|
||||
|
||||
vector<PlateLine> hlines = this->getLines(edges, sensitivity, false);
|
||||
vector<PlateLine> vlines = this->getLines(edges, sensitivity, true);
|
||||
for (uint i = 0; i < hlines.size(); i++)
|
||||
this->horizontalLines.push_back(hlines[i]);
|
||||
for (uint i = 0; i < vlines.size(); i++)
|
||||
this->verticalLines.push_back(vlines[i]);
|
||||
|
||||
// if debug is enabled, draw the image
|
||||
if (this->debug)
|
||||
PlateLines::~PlateLines()
|
||||
{
|
||||
Mat debugImgHoriz(edges.size(), edges.type());
|
||||
Mat debugImgVert(edges.size(), edges.type());
|
||||
edges.copyTo(debugImgHoriz);
|
||||
edges.copyTo(debugImgVert);
|
||||
cvtColor(debugImgHoriz,debugImgHoriz,CV_GRAY2BGR);
|
||||
cvtColor(debugImgVert,debugImgVert,CV_GRAY2BGR);
|
||||
}
|
||||
|
||||
for( size_t i = 0; i < this->horizontalLines.size(); i++ )
|
||||
void PlateLines::processImage(Mat inputImage, vector<TextLine> textLines, float sensitivity)
|
||||
{
|
||||
if (this->debug)
|
||||
cout << "PlateLines findLines" << endl;
|
||||
|
||||
timespec startTime;
|
||||
getTime(&startTime);
|
||||
|
||||
|
||||
// Ignore input images that are pure white or pure black
|
||||
Scalar avgPixelIntensity = mean(inputImage);
|
||||
if (avgPixelIntensity[0] == 255)
|
||||
return;
|
||||
else if (avgPixelIntensity[0] == 0)
|
||||
return;
|
||||
|
||||
// Do a bilateral filter to clean the noise but keep edges sharp
|
||||
Mat smoothed(inputImage.size(), inputImage.type());
|
||||
adaptiveBilateralFilter(inputImage, smoothed, Size(3,3), 45, 45);
|
||||
|
||||
|
||||
int morph_elem = 2;
|
||||
int morph_size = 2;
|
||||
Mat element = getStructuringElement( morph_elem, Size( 2*morph_size + 1, 2*morph_size+1 ), Point( morph_size, morph_size ) );
|
||||
|
||||
|
||||
Mat edges(inputImage.size(), inputImage.type());
|
||||
Canny(smoothed, edges, 66, 133);
|
||||
|
||||
// Create a mask that is dilated based on the detected characters
|
||||
|
||||
|
||||
Mat mask = Mat::zeros(inputImage.size(), CV_8U);
|
||||
|
||||
for (uint i = 0; i < textLines.size(); i++)
|
||||
{
|
||||
line( debugImgHoriz, this->horizontalLines[i].line.p1, this->horizontalLines[i].line.p2, Scalar(0,0,255), 1, CV_AA);
|
||||
vector<vector<Point> > polygons;
|
||||
polygons.push_back(textLines[i].textArea);
|
||||
fillPoly(mask, polygons, Scalar(255,255,255));
|
||||
}
|
||||
|
||||
for( size_t i = 0; i < this->verticalLines.size(); i++ )
|
||||
|
||||
|
||||
dilate(mask, mask, getStructuringElement( 1, Size( 1 + 1, 2*1+1 ), Point( 1, 1 ) ));
|
||||
bitwise_not(mask, mask);
|
||||
|
||||
// AND canny edges with the character mask
|
||||
bitwise_and(edges, mask, edges);
|
||||
|
||||
|
||||
vector<PlateLine> hlines = this->getLines(edges, sensitivity, false);
|
||||
vector<PlateLine> vlines = this->getLines(edges, sensitivity, true);
|
||||
for (uint i = 0; i < hlines.size(); i++)
|
||||
this->horizontalLines.push_back(hlines[i]);
|
||||
for (uint i = 0; i < vlines.size(); i++)
|
||||
this->verticalLines.push_back(vlines[i]);
|
||||
|
||||
// if debug is enabled, draw the image
|
||||
if (this->debug)
|
||||
{
|
||||
line( debugImgVert, this->verticalLines[i].line.p1, this->verticalLines[i].line.p2, Scalar(0,0,255), 1, CV_AA);
|
||||
Mat debugImgHoriz(edges.size(), edges.type());
|
||||
Mat debugImgVert(edges.size(), edges.type());
|
||||
edges.copyTo(debugImgHoriz);
|
||||
edges.copyTo(debugImgVert);
|
||||
cvtColor(debugImgHoriz,debugImgHoriz,CV_GRAY2BGR);
|
||||
cvtColor(debugImgVert,debugImgVert,CV_GRAY2BGR);
|
||||
|
||||
for( size_t i = 0; i < this->horizontalLines.size(); i++ )
|
||||
{
|
||||
line( debugImgHoriz, this->horizontalLines[i].line.p1, this->horizontalLines[i].line.p2, Scalar(0,0,255), 1, CV_AA);
|
||||
}
|
||||
|
||||
for( size_t i = 0; i < this->verticalLines.size(); i++ )
|
||||
{
|
||||
line( debugImgVert, this->verticalLines[i].line.p1, this->verticalLines[i].line.p2, Scalar(0,0,255), 1, CV_AA);
|
||||
}
|
||||
|
||||
vector<Mat> images;
|
||||
images.push_back(debugImgHoriz);
|
||||
images.push_back(debugImgVert);
|
||||
|
||||
Mat dashboard = drawImageDashboard(images, debugImgVert.type(), 1);
|
||||
displayImage(pipelineData->config, "Hough Lines", dashboard);
|
||||
}
|
||||
|
||||
vector<Mat> images;
|
||||
images.push_back(debugImgHoriz);
|
||||
images.push_back(debugImgVert);
|
||||
if (pipelineData->config->debugTiming)
|
||||
{
|
||||
timespec endTime;
|
||||
getTime(&endTime);
|
||||
cout << "Plate Lines Time: " << diffclock(startTime, endTime) << "ms." << endl;
|
||||
}
|
||||
|
||||
Mat dashboard = drawImageDashboard(images, debugImgVert.type(), 1);
|
||||
displayImage(pipelineData->config, "Hough Lines", dashboard);
|
||||
}
|
||||
|
||||
if (pipelineData->config->debugTiming)
|
||||
|
||||
|
||||
|
||||
vector<PlateLine> PlateLines::getLines(Mat edges, float sensitivityMultiplier, bool vertical)
|
||||
{
|
||||
timespec endTime;
|
||||
getTime(&endTime);
|
||||
cout << "Plate Lines Time: " << diffclock(startTime, endTime) << "ms." << endl;
|
||||
}
|
||||
if (this->debug)
|
||||
cout << "PlateLines::getLines" << endl;
|
||||
|
||||
}
|
||||
static int HORIZONTAL_SENSITIVITY = pipelineData->config->plateLinesSensitivityHorizontal;
|
||||
static int VERTICAL_SENSITIVITY = pipelineData->config->plateLinesSensitivityVertical;
|
||||
|
||||
vector<Vec2f> allLines;
|
||||
vector<PlateLine> filteredLines;
|
||||
|
||||
|
||||
|
||||
vector<PlateLine> PlateLines::getLines(Mat edges, float sensitivityMultiplier, bool vertical)
|
||||
{
|
||||
if (this->debug)
|
||||
cout << "PlateLines::getLines" << endl;
|
||||
|
||||
static int HORIZONTAL_SENSITIVITY = pipelineData->config->plateLinesSensitivityHorizontal;
|
||||
static int VERTICAL_SENSITIVITY = pipelineData->config->plateLinesSensitivityVertical;
|
||||
|
||||
vector<Vec2f> allLines;
|
||||
vector<PlateLine> filteredLines;
|
||||
|
||||
int sensitivity;
|
||||
if (vertical)
|
||||
sensitivity = VERTICAL_SENSITIVITY * (1.0 / sensitivityMultiplier);
|
||||
else
|
||||
sensitivity = HORIZONTAL_SENSITIVITY * (1.0 / sensitivityMultiplier);
|
||||
|
||||
HoughLines( edges, allLines, 1, CV_PI/180, sensitivity, 0, 0 );
|
||||
|
||||
for( size_t i = 0; i < allLines.size(); i++ )
|
||||
{
|
||||
float rho = allLines[i][0], theta = allLines[i][1];
|
||||
Point pt1, pt2;
|
||||
double a = cos(theta), b = sin(theta);
|
||||
double x0 = a*rho, y0 = b*rho;
|
||||
|
||||
double angle = theta * (180 / CV_PI);
|
||||
pt1.x = cvRound(x0 + 1000*(-b));
|
||||
pt1.y = cvRound(y0 + 1000*(a));
|
||||
pt2.x = cvRound(x0 - 1000*(-b));
|
||||
pt2.y = cvRound(y0 - 1000*(a));
|
||||
|
||||
int sensitivity;
|
||||
if (vertical)
|
||||
{
|
||||
if (angle < 20 || angle > 340 || (angle > 160 && angle < 210))
|
||||
{
|
||||
// good vertical
|
||||
|
||||
LineSegment line;
|
||||
if (pt1.y <= pt2.y)
|
||||
line = LineSegment(pt2.x, pt2.y, pt1.x, pt1.y);
|
||||
else
|
||||
line = LineSegment(pt1.x, pt1.y, pt2.x, pt2.y);
|
||||
|
||||
// Get rid of the -1000, 1000 stuff. Terminate at the edges of the image
|
||||
// Helps with debugging/rounding issues later
|
||||
LineSegment top(0, 0, edges.cols, 0);
|
||||
LineSegment bottom(0, edges.rows, edges.cols, edges.rows);
|
||||
Point p1 = line.intersection(bottom);
|
||||
Point p2 = line.intersection(top);
|
||||
|
||||
PlateLine plateLine;
|
||||
plateLine.line = LineSegment(p1.x, p1.y, p2.x, p2.y);
|
||||
plateLine.confidence = (1.0 - MIN_CONFIDENCE) * ((float) (allLines.size() - i)) / ((float)allLines.size()) + MIN_CONFIDENCE;
|
||||
filteredLines.push_back(plateLine);
|
||||
}
|
||||
}
|
||||
sensitivity = VERTICAL_SENSITIVITY * (1.0 / sensitivityMultiplier);
|
||||
else
|
||||
sensitivity = HORIZONTAL_SENSITIVITY * (1.0 / sensitivityMultiplier);
|
||||
|
||||
HoughLines( edges, allLines, 1, CV_PI/180, sensitivity, 0, 0 );
|
||||
|
||||
for( size_t i = 0; i < allLines.size(); i++ )
|
||||
{
|
||||
if ( (angle > 70 && angle < 110) || (angle > 250 && angle < 290))
|
||||
float rho = allLines[i][0], theta = allLines[i][1];
|
||||
Point pt1, pt2;
|
||||
double a = cos(theta), b = sin(theta);
|
||||
double x0 = a*rho, y0 = b*rho;
|
||||
|
||||
double angle = theta * (180 / CV_PI);
|
||||
pt1.x = cvRound(x0 + 1000*(-b));
|
||||
pt1.y = cvRound(y0 + 1000*(a));
|
||||
pt2.x = cvRound(x0 - 1000*(-b));
|
||||
pt2.y = cvRound(y0 - 1000*(a));
|
||||
|
||||
if (vertical)
|
||||
{
|
||||
// good horizontal
|
||||
if (angle < 20 || angle > 340 || (angle > 160 && angle < 210))
|
||||
{
|
||||
// good vertical
|
||||
|
||||
LineSegment line;
|
||||
if (pt1.x <= pt2.x)
|
||||
line = LineSegment(pt1.x, pt1.y, pt2.x, pt2.y);
|
||||
else
|
||||
line =LineSegment(pt2.x, pt2.y, pt1.x, pt1.y);
|
||||
LineSegment line;
|
||||
if (pt1.y <= pt2.y)
|
||||
line = LineSegment(pt2.x, pt2.y, pt1.x, pt1.y);
|
||||
else
|
||||
line = LineSegment(pt1.x, pt1.y, pt2.x, pt2.y);
|
||||
|
||||
// Get rid of the -1000, 1000 stuff. Terminate at the edges of the image
|
||||
// Helps with debugging/ rounding issues later
|
||||
int newY1 = line.getPointAt(0);
|
||||
int newY2 = line.getPointAt(edges.cols);
|
||||
// Get rid of the -1000, 1000 stuff. Terminate at the edges of the image
|
||||
// Helps with debugging/rounding issues later
|
||||
LineSegment top(0, 0, edges.cols, 0);
|
||||
LineSegment bottom(0, edges.rows, edges.cols, edges.rows);
|
||||
Point p1 = line.intersection(bottom);
|
||||
Point p2 = line.intersection(top);
|
||||
|
||||
PlateLine plateLine;
|
||||
plateLine.line = LineSegment(0, newY1, edges.cols, newY2);
|
||||
plateLine.confidence = (1.0 - MIN_CONFIDENCE) * ((float) (allLines.size() - i)) / ((float)allLines.size()) + MIN_CONFIDENCE;
|
||||
filteredLines.push_back(plateLine);
|
||||
PlateLine plateLine;
|
||||
plateLine.line = LineSegment(p1.x, p1.y, p2.x, p2.y);
|
||||
plateLine.confidence = (1.0 - MIN_CONFIDENCE) * ((float) (allLines.size() - i)) / ((float)allLines.size()) + MIN_CONFIDENCE;
|
||||
filteredLines.push_back(plateLine);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( (angle > 70 && angle < 110) || (angle > 250 && angle < 290))
|
||||
{
|
||||
// good horizontal
|
||||
|
||||
LineSegment line;
|
||||
if (pt1.x <= pt2.x)
|
||||
line = LineSegment(pt1.x, pt1.y, pt2.x, pt2.y);
|
||||
else
|
||||
line =LineSegment(pt2.x, pt2.y, pt1.x, pt1.y);
|
||||
|
||||
// Get rid of the -1000, 1000 stuff. Terminate at the edges of the image
|
||||
// Helps with debugging/ rounding issues later
|
||||
int newY1 = line.getPointAt(0);
|
||||
int newY2 = line.getPointAt(edges.cols);
|
||||
|
||||
PlateLine plateLine;
|
||||
plateLine.line = LineSegment(0, newY1, edges.cols, newY2);
|
||||
plateLine.confidence = (1.0 - MIN_CONFIDENCE) * ((float) (allLines.size() - i)) / ((float)allLines.size()) + MIN_CONFIDENCE;
|
||||
filteredLines.push_back(plateLine);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return filteredLines;
|
||||
}
|
||||
|
||||
return filteredLines;
|
||||
}
|
||||
|
||||
Mat PlateLines::customGrayscaleConversion(Mat src)
|
||||
{
|
||||
Mat img_hsv;
|
||||
cvtColor(src,img_hsv,CV_BGR2HSV);
|
||||
|
||||
Mat grayscale = Mat(img_hsv.size(), CV_8U );
|
||||
Mat hue(img_hsv.size(), CV_8U );
|
||||
|
||||
for (int row = 0; row < img_hsv.rows; row++)
|
||||
Mat PlateLines::customGrayscaleConversion(Mat src)
|
||||
{
|
||||
for (int col = 0; col < img_hsv.cols; col++)
|
||||
Mat img_hsv;
|
||||
cvtColor(src,img_hsv,CV_BGR2HSV);
|
||||
|
||||
Mat grayscale = Mat(img_hsv.size(), CV_8U );
|
||||
Mat hue(img_hsv.size(), CV_8U );
|
||||
|
||||
for (int row = 0; row < img_hsv.rows; row++)
|
||||
{
|
||||
int h = (int) img_hsv.at<Vec3b>(row, col)[0];
|
||||
//int s = (int) img_hsv.at<Vec3b>(row, col)[1];
|
||||
int v = (int) img_hsv.at<Vec3b>(row, col)[2];
|
||||
for (int col = 0; col < img_hsv.cols; col++)
|
||||
{
|
||||
int h = (int) img_hsv.at<Vec3b>(row, col)[0];
|
||||
//int s = (int) img_hsv.at<Vec3b>(row, col)[1];
|
||||
int v = (int) img_hsv.at<Vec3b>(row, col)[2];
|
||||
|
||||
int pixval = pow(v, 1.05);
|
||||
int pixval = pow(v, 1.05);
|
||||
|
||||
if (pixval > 255)
|
||||
pixval = 255;
|
||||
grayscale.at<uchar>(row, col) = pixval;
|
||||
if (pixval > 255)
|
||||
pixval = 255;
|
||||
grayscale.at<uchar>(row, col) = pixval;
|
||||
|
||||
hue.at<uchar>(row, col) = h * (255.0 / 180.0);
|
||||
hue.at<uchar>(row, col) = h * (255.0 / 180.0);
|
||||
}
|
||||
}
|
||||
|
||||
//displayImage(config, "Hue", hue);
|
||||
return grayscale;
|
||||
}
|
||||
|
||||
//displayImage(config, "Hue", hue);
|
||||
return grayscale;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user