
srcnativelibs.Vision.cvgui.cpp Maven / Gradle / Ivy
/*
* Copyright 2010-2014, Sikuli.org, sikulix.com
* Released under the MIT License.
*
*/
#include "cvgui.h"
#include "sikuli-debug.h"
#include
using namespace std;
using namespace sikuli;
Scalar Color::RED(0,0,255);
Scalar Color::WHITE(255,255,255);
Scalar Color::RANDOM() {
return Scalar(rand()&255, rand()&255, rand()&255);
};
static bool sort_by_x (Rect a, Rect b){
return (a.x < b.x);
}
static bool sort_blob_by_x(Blob a, Blob b){
return (a.x < b.x);
}
static bool sort_blob_by_y(Blob a, Blob b){
return (a.y < b.y);
}
#define SHOW(x) namedWindow(#x,1); imshow(#x,x);
#define SHOW0(x) namedWindow(#x,1); imshow(#x,x); waitKey(0);
//class VisualLogger{
//
//
// int image_i;
// int step_i;
// char* prefix;
//
//public:
//
// VisualLogger(){
// }
//
// static void newImage(){
// image_i++;
// step_i = 0;
// }
//
// static void log(const char* name, const Mat& image){
// char buf[200];
//
// if (prefix){
//
// sprintf(buf, "%s-%02d-%s.vlog.png", prefix, step_i, name);
//
// }else{
// sprintf(buf, "%03d-%02d-%s.vlog.png",image_i,step_i,name);
// }
//
// imwrite(buf, image);
//
// step_i++;
// }
//};
//
//static VisualLogger vlog;
int VisualLogger::image_i = 0;
int VisualLogger::step_i = 0;
//bool VisualLogger::enabled = false;
char* VisualLogger::prefix = 0;
//#define VLOG(x,y)
void
Util::rgb2grayC3(const Mat& input, Mat& output){
Mat g;
cvtColor(input, g, CV_RGB2GRAY);
Mat ss[3] = {g,g,g};
merge(ss,3,output);
}
void
Util::growRect(Rect& rect, int xd, int yd, Rect bounds){
Rect in = rect;
in.x -= xd;
in.width += 2*xd;
in.y -= yd;
in.height += 2*yd;
int x1 = max(bounds.x, in.x);
int y1 = max(bounds.y, in.y);
int x2 = min(in.x + in.width, bounds.width);
int y2 = min(in.y + in.height, bounds.height);
if (x2 < x1 || y2 < y1)
rect = Rect(0,0,0,0);
else
rect = Rect(x1,y1,x2-x1+1,y2-y1+1);
}
void
Util::growRect(Rect& rect, int xd, int yd, cv::Mat image){
growRect(rect, xd, yd, Rect(0,0, image.cols-1, image.rows-1));
}
void
Painter::drawRect(Mat& image, Rect r, Scalar color){
rectangle(image,
Point(r.x, r.y),
Point(r.x + r.width, r.y + r.height),
color);
}
void
Painter::drawRect(Mat& image, OCRRect r, Scalar color){
rectangle(image,
Point(r.x, r.y),
Point(r.x + r.width, r.y + r.height),
color);
}
void
Painter::drawRects(Mat& image, vector& rects, Scalar color){
for (vector::iterator r = rects.begin();
r != rects.end(); ++r){
rectangle(image,
Point(r->x, r->y),
Point(r->x + r->width, r->y + r->height),
color);
}
}
void
Painter::drawBlobsRandomShading(Mat& image, vector& blobs){
Mat blank = image.clone();
blank = 0.0;
Mat shading = blank;
for (vector::iterator it = blobs.begin();
it != blobs.end(); ++it){
Blob& box = *it;
rectangle(shading, Point(box.x,box.y), Point(box.x+box.width,box.y+box.height), Color::RANDOM(), CV_FILLED);
}
image = image * 0.5 + shading * 0.7;
Painter::drawBlobs(image, blobs, Color::WHITE);
}
void
Painter::drawRects(Mat& image, vector& rects){
drawRects(image, rects, Scalar(0,0,255));
}
void
Painter::drawBlobs(Mat& image, vector& blobs){
for (vector::iterator it = blobs.begin();
it != blobs.end(); ++it){
Blob& blob = *it;
Scalar color(blob.mr,blob.mg,blob.mb);
vector rs;
rs.push_back(blob);
drawRects(image, rs, color);
}
}
void
Painter::drawBlobs(Mat& image, vector& blobs, Scalar color){
vector rs;
for (vector::iterator it = blobs.begin();
it != blobs.end(); ++it){
Blob& blob = *it;
rs.push_back(blob);
}
drawRects(image, rs, color);
}
void
Painter::drawLineBlobs(Mat& image, vector& lineblobs, Scalar color){
for (vector::iterator it1 = lineblobs.begin();
it1 != lineblobs.end(); ++it1){
LineBlob& lineblob = *it1;
if (lineblob.blobs.size()>=2){
for (vector::iterator r = lineblob.blobs.begin() + 1;
r != lineblob.blobs.end(); ++r){
Rect previous = *(r-1);
Rect current = *r;
Point from(previous.x+previous.width,previous.y);
Point to(current.x,current.y);
cv::line(image, from, to, Scalar(255,255,255));
}
}
drawRect(image, lineblob, color);
}
}
void
Painter::drawParagraphBlobs(Mat& image, vector blobs, Scalar color){
for (vector::iterator it = blobs.begin();
it != blobs.end(); ++it){
ParagraphBlob& parablob = *it;
for (vector::iterator it1 = parablob.lineblobs.begin();
it1 != parablob.lineblobs.end(); ++it1){
LineBlob& lineblob = *it1;
drawRect(image, lineblob, Scalar(255,255,0));
}
drawRect(image, parablob, Scalar(0,0,255));
}
}
void
Painter::drawOCRWord(Mat& ocr_result_image, OCRWord ocrword){
cout << ocrword.x << " " << ocrword.y << " " << ocrword.width << " " << ocrword.height << ": ";
cout << ocrword.getString() << endl;
drawRect(ocr_result_image, ocrword, Scalar(255,255,0));
Point pt(ocrword.x, ocrword.y + ocrword.height - 10);
putText(ocr_result_image, ocrword.getString(), pt,
FONT_HERSHEY_SIMPLEX, 0.4, Color::RED);
}
void
Painter::drawOCRLine(Mat& ocr_result_image, OCRLine ocrline){
vector ocrwords = ocrline.getWords();
for (vector::iterator it = ocrwords.begin(); it != ocrwords.end(); ++it){
OCRWord& ocrword = *it;
drawOCRWord(ocr_result_image, ocrword);
}
}
void
Painter::drawOCRParagraph(Mat& ocr_result_image, OCRParagraph ocrpara){
vector ocrlines = ocrpara.getLines();
for (vector::iterator it = ocrlines.begin(); it != ocrlines.end(); ++it){
OCRLine& ocrline = *it;
drawOCRLine(ocr_result_image, ocrline);
}
}
void
Painter::drawOCRText(Mat& ocr_result_image, OCRText ocrtext){
vector ocrparas = ocrtext.getParagraphs();
for (vector::iterator it = ocrparas.begin(); it != ocrparas.end(); ++it){
OCRParagraph& ocrpara = *it;
drawOCRParagraph(ocr_result_image, ocrpara);
}
}
void
LineBlob::merge(LineBlob& blob){
for (vector::iterator it = blob.blobs.begin();
it != blob.blobs.end(); ++it){
add(*it);
}
}
void
LineBlob::updateBoundingRect(Blob& blob){
if (blobs.size() == 0){
x = blob.x;
y = blob.y;
height = blob.height;
width = blob.width;
}else{
int x1,y1,x2,y2;
x1 = min(x, blob.x);
y1 = min(y, blob.y);
x2 = max(x+width, blob.x + blob.width);
y2 = max(y+height, blob.y + blob.height);
x = x1;
y = y1;
height = y2 - y1;
width = x2 - x1;
}
}
void
LineBlob::add(Blob& blob){
updateBoundingRect(blob);
blobs.push_back(blob);
}
void
LineBlob::calculateBoundingRectangle(){
int x1,y1,x2,y2;
Blob& first_blob = blobs.front();
x1 = first_blob.x;
x2 = first_blob.x + first_blob.width;
y1 = first_blob.y;
y2 = first_blob.y + first_blob.height;
for (vector::iterator it_line = blobs.begin()+1;
it_line != blobs.end(); ++it_line){
Blob& b = *it_line;
x1 = min(x1, b.x);
y1 = min(y1, b.y);
x2 = max(x2, b.x + b.width);
y2 = max(y2, b.y + b.height);
}
x = x1;
y = y1;
height = y2 - y1;
width = x2 - x1;
}
void
ParagraphBlob::add(LineBlob& blob){
if (lineblobs.size() == 0){
x = blob.x;
y = blob.y;
height = blob.height;
width = blob.width;
}else{
int x1,y1,x2,y2;
x1 = min(x, blob.x);
y1 = min(y, blob.y);
x2 = max(x+width, blob.x + blob.width);
y2 = max(y+height, blob.y + blob.height);
x = x1;
y = y1;
height = y2 - y1;
width = x2 - x1;
}
lineblobs.push_back(blob);
}
void denoise(Mat& src){
//src = src * 0.1;
Mat kernel = Mat::ones(3,3,CV_32FC1);
kernel.at(2,2) = 0;
Mat srcF, destF;
src.convertTo(srcF, CV_32FC1, 0.1);
filter2D(srcF, destF, -1, kernel);
Mat destU;
destF.convertTo(destU, CV_8UC1);
threshold(destU, destU, 60, 255, THRESH_BINARY);
bitwise_and(src, destU, src);
}
void
cvgui::linkLineBlobsIntoPagagraphBlobs(vector& blobs, vector& parablobs){
sort(blobs, sort_blob_by_y);
for (vector::iterator it = blobs.begin();
it != blobs.end(); ++it){
LineBlob& blob = *it;
vector::iterator it1;
for (it1 = parablobs.begin();
it1 != parablobs.end(); ++it1){
ParagraphBlob& parablob = *it1;
bool left_aligned = abs(parablob.x - blob.x) < 10;
bool small_vertical_spacing = abs(blob.y - (parablob.y + parablob.height)) < 15;
bool same_paragraph = left_aligned & small_vertical_spacing;
if (same_paragraph){
parablob.add(blob);
break;
}
}
if (it1 == parablobs.end()){
ParagraphBlob new_parablob;
new_parablob.add(blob);
parablobs.push_back(new_parablob);
}
}
}
void
cvgui::mergeLineBlobs(vector& blobs, vector& merged_blobs){
sort(blobs, sort_blob_by_x);
for (vector::iterator it = blobs.begin();
it != blobs.end(); ++it){
LineBlob& blob = *it;
vector::iterator l;
for (l = merged_blobs.begin(); l != merged_blobs.end(); ++l){
LineBlob& merged_blob = *l;
bool similar_baseline = abs((merged_blob.y + merged_blob.height) - (blob.y + blob.height)) < 5;
bool small_spacing = (blob.x - (merged_blob.x + merged_blob.width)) < 10;
bool cond1 = merged_blob.isContainedBy(blob) || blob.isContainedBy(merged_blob);
bool same_line = cond1 || (similar_baseline && small_spacing);
if (same_line){
merged_blob.merge(blob);
break;
}
}
if (l == merged_blobs.end()){
merged_blobs.push_back(blob);
}
}
}
void
cvgui::linkBlobsIntoLineBlobs(vector& blobs, vector& lines, int max_spacing){
sort(blobs, sort_blob_by_x);
for (vector::iterator it = blobs.begin();
it != blobs.end(); ++it){
Blob& blob = *it;
vector::iterator l;
for (l = lines.begin(); l != lines.end(); ++l){
LineBlob& line = *l;
Blob& last = line.blobs.back();
bool similar_baseline = abs((last.y + last.height) - (blob.y + blob.height)) < 5;
bool similar_centerline = abs((last.y + last.height/2) - (blob.y + blob.height/2)) < 5;
bool similar_height = 1.0*min(last.height,blob.height)/max(last.height,blob.height) > 0.5;
bool similar_width = 1.0*min(last.width,blob.width)/max(last.width,blob.width) > 0.5;
bool small_overlap = blob.x > ((last.x + last.width)-2);
bool small_spacing = (blob.x - (last.x + last.width)) < max_spacing;
bool is_dot = blob.height < 3 && blob.width < 3 && similar_baseline && small_spacing;
int th = 40;
bool similar_foreground_color =
abs(last.mr - blob.mr) < th && abs(last.mg - blob.mg) < th && abs(last.mb - blob.mb) < th;
//bool is_probably_i = blob.width < 2 || last.width < 2;
bool same_line = (similar_centerline || similar_baseline)
&& similar_height
&& small_overlap
//&& similar_width
&& small_spacing
&& similar_foreground_color; //|| is_probably_i);
bool very_close = (blob.x - (last.x + last.width)) < 3;
// bool vertically_overlap = similar_baseline;
if (same_line || (very_close && similar_height && similar_baseline)){
line.add(blob);
break;
}
}
if (l == lines.end()){
LineBlob newline;
newline.add(blob);
lines.push_back(newline);
}
}
}
void
cvgui::run_ocr_on_lineblobs(vector& ocr_input_lineblobs,
Mat& input_image,
vector& ocrlines){
for (vector::iterator it = ocr_input_lineblobs.begin();
it != ocr_input_lineblobs.end(); ++it){
LineBlob& lineblob = *it;
OCRLine ocrline;
OCRWord ocrword;
// if (lineblob.blobs.size()<10)
// continue;
//
Mat wordImage(input_image,lineblob);
Mat ocrImage; // the image passed to tesseract
bool upsampled = false;
if (wordImage.rows < 20){
upsampled = true;
resize(wordImage, ocrImage, Size(wordImage.cols*2,wordImage.rows*2));
}else {
ocrImage = wordImage.clone();
}
vector ocr_chars;
ocr_chars = OCR::recognize((unsigned char*)ocrImage.data,
ocrImage.cols,
ocrImage.rows,
8);
for (vector::iterator iter = ocr_chars.begin();
iter != ocr_chars.end(); iter++){
OCRChar& ocrchar = *iter;
if (upsampled){
// scale back the coordinates in the OCR result
ocrchar.x = ocrchar.x/2;
ocrchar.y = ocrchar.y/2;
ocrchar.width = ocrchar.width/2;
ocrchar.height = ocrchar.height/2;
}
ocrchar.x += lineblob.x;
ocrchar.y += lineblob.y;
if (iter > ocr_chars.begin()){
OCRChar& previous_ocrchar = *(iter-1);
int spacing = ocrchar.x - (previous_ocrchar.x + previous_ocrchar.width);
//dout() << '[' << ocrchar.height << ':' << spacing << ']';
//dout() << '[' << spacing << ']';
if (lineblob.height > 6 && spacing >= 4){// || spacing >= 2){
ocrline.addWord(ocrword);
ocrword.clear();
//dout() << ' ';
}
}
//dout() << ocrchar.ch;
ocrword.add(ocrchar);
ocrword.y = lineblob.y;
ocrword.height = lineblob.height;
}
ocrline.addWord(ocrword);
//dout() << endl;
ocrlines.push_back(ocrline);
}
}
void getLeafBlobs(vector& blobs, vector& leaf_blobs){
leaf_blobs.clear();
for (vector::iterator it = blobs.begin();
it != blobs.end(); ++it){
Blob& a = *it;
// check if blob 'a' contains any other blob
vector::iterator it1;
for (it1 = blobs.begin();
it1 != blobs.end(); ++it1){
Blob& b = *it1;
if (it != it1 && b.isContainedBy(a))
break;
}
// if not, it is a leave blob
if (it1 == blobs.end())
leaf_blobs.push_back(a);
}
}
Mat
cvgui::findBoxesByVoting(const Mat& screen,
int bw, int bh,
vector& output_blobs){
Mat dark;
Util::rgb2grayC3(screen,dark);
dark = dark * 0.5;
VLOG("Input", screen);
Mat gray;
cvtColor(screen,gray,CV_RGB2GRAY);
// Code for experimenting differenty parameters for Canny
// for (int c=10;c<=100;c=c+10){
// char buf[50];
// Mat test;
// sprintf(buf,"Canny%d",c);
// Canny(gray,test,0.66*c,1.33*c,3,true);
// VLOG(buf, test);
// }
Mat canny;
int s = 200;
Canny(gray,canny,0.66*s,1.33*s,3,true);
VLOG("Canny", canny);
Mat edges;
Mat v = Mat::ones(2,2,CV_8UC1);
dilate(canny, edges, v);
erode(edges, edges, v);
dilate(edges, edges, Mat::ones(3,3,CV_8UC1));
VLOG("Dilated", edges);
double k = 0.85;
double tol = 0.10;
Mat q = Mat::ones(5,5,CV_8UC1);
Mat h1,h2,hvotes;
voteCenter_Horizontal(edges, h1, bw*k, bw*tol, bh/2);
dilate(h1, h1, q);
voteCenter_Horizontal(edges, h2, bw*k, bw*tol, -bh/2);
dilate(h2, h2, q);
bitwise_and(h1,h2,hvotes);
VLOG("H-votes", hvotes);
Mat v1,v2,vvotes;
voteCenter_Vertical(edges, v1, bh*k, bh*tol, bw/2);
dilate(v1, v1, q);
voteCenter_Vertical(edges, v2, bh*k, bh*tol, -bw/2);
dilate(v2, v2, q);
bitwise_and(v1,v2,vvotes);
VLOG("V-votes", vvotes);
Mat hvvotes;
bitwise_and(vvotes,hvotes,hvvotes);
VLOG("HV-votes", hvvotes);
Mat copy = hvvotes.clone();
vector > contours;
vector hierarchy;
findContours( copy, contours, hierarchy,
CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );
vector blobs;
Mat blank = dark.clone();
blank = 0.0;
Mat contour_shading = blank;
// define a perfect box for back-proj verification
Mat pbox = Mat::zeros(bh,bw,CV_8UC1);
pbox.row(0).setTo(255);
pbox.row(bh-1).setTo(255);
pbox.col(0).setTo(255);
pbox.col(bw-1).setTo(255);
int pscore = countNonZero(pbox);
for (vector >::iterator it = contours.begin();
it != contours.end(); ++it){
vector& contour = *it;
Rect r = boundingRect(Mat(contour));
double a1 = contourArea(Mat(contour));
double a2 = r.height * r.width;
int cx = r.x + r.width/2;
int cy = r.y + r.height/2;
Rect box(cx-bw/2,cy-bh/2,bw,bh);
Mat e(edges, box);
// calculate the score by comparing each hypothesized box to the ideal box
Mat sc;
bitwise_and(e,pbox,sc);
int score = countNonZero(sc);
// ignore those boxes with fewer than this percentage
// of edge pixels
if ((1.0 * score) / (1.0 * pscore) < 0.90)
continue;
// rectangle(contour_shading, Point(box.x,box.y), Point(box.x+box.width,box.y+box.height), Color::RANDOM(), CV_FILLED);
Blob blob(box);
blob.score = score;
blobs.push_back(blob);
}
Mat blobs_image = dark.clone();
Painter::drawBlobsRandomShading(blobs_image, blobs);
VLOG("BlobHypotheses", blobs_image);
// remove overlapping blobs
// and do non-maximal suppression
vector nonoverlapping_blobs;
for (vector::iterator it = blobs.begin();
it != blobs.end(); ++it){
Blob& b = *it;
bool not_overlap = true;
int tolerance = 3;
vector::iterator ito;
for (ito = nonoverlapping_blobs.begin();
ito != nonoverlapping_blobs.end(); ++ito){
Blob& bo = *ito;
not_overlap = b.x >= bo.x + bo.width - tolerance || b.y >= bo.y + bo.height - tolerance||
b.x + b.width <= bo.x + tolerance|| b.y + b.height <= bo.y + tolerance;
if (!not_overlap)
break;
}
if (not_overlap){
nonoverlapping_blobs.push_back(b);
}else{
// replace it if the score is better
if (it->score > ito->score){
(*ito) = (*it);
}
}
}
vector& result_blobs = nonoverlapping_blobs;
Mat result_blobs_image = dark.clone();
Painter::drawBlobsRandomShading(result_blobs_image, result_blobs);
VLOG("OutputBlobs", result_blobs_image);
// print output to stdout
for (vector::iterator it = result_blobs.begin();
it != result_blobs.end(); ++it){
Blob& b = *it;
dout() << b.x << " " << b.y << " " << b.width << " " << b.height << " " << b.score << endl;
}
return result_blobs_image;
}
Mat
cvgui::findPokerBoxes(const Mat& screen, vector& output_blobs){
//return findBoxesByVoting(screen, 70, 90, output_blobs);
return findBoxesByVoting(screen, 40, 50, output_blobs);
// old algorithm
#if 0
Mat dark;
Util::rgb2grayC3(screen,dark);
dark = dark * 0.5;
VLOG("Input", screen);
Mat gray;
cvtColor(screen,gray,CV_RGB2GRAY);
//medianBlur(gray, gray, 3);
//VLOG("Blurred", gray);
Mat edges;
// Code for experimenting differenty parameters for Canny
// for (int c=10;c<=100;c=c+10){
// char buf[50];
// Mat test;
// sprintf(buf,"Canny%d",c);
// Canny(gray,test,0.66*c,1.33*c,3,true);
// VLOG(buf, test);
// }
int s = 100;
Canny(gray,edges,0.66*s,1.33*s,3,true);
VLOG("Canny", edges);
Mat v = Mat::ones(2,2,CV_8UC1);
dilate(edges, edges, v);
erode(edges, edges, v);
VLOG("Dilated", edges);
// experimental
Mat hlines,vlines;
dilate(edges, edges, Mat::ones(3,2,CV_8UC1));
findLongLines_Vertical(edges,vlines, 50, 2);
VLOG("V-lines", vlines);
findLongLines_Horizontal(edges,hlines, 50, 2);
VLOG("H-lines", hlines);
int bw = 70;
int bh = 20;
double k = 0.90;
Mat q = Mat::ones(5,5,CV_8UC1);
Mat h1,h2,hvotes;
voteCenter_Horizontal(edges, h1, bw*k, 2, bh/2);
dilate(h1, h1, q);
voteCenter_Horizontal(edges, h2, bw*k, 2, -bh/2);
dilate(h2, h2, q);
bitwise_and(h1,h2,hvotes);
VLOG("H-votes", hvotes);
Mat v1,v2,vvotes;
voteCenter_Vertical(edges, v1, bh*k, 2, bw/2);
dilate(v1, v1, q);
voteCenter_Vertical(edges, v2, bh*k, 2, -bw/2);
dilate(v2, v2, q);
bitwise_and(v1,v2,vvotes);
VLOG("V-votes", vvotes);
Mat hvvotes;
bitwise_and(vvotes,hvotes,hvvotes);
VLOG("HV-votes", hvvotes);
// Mat hvlines;
// bitwise_or(hlines, vlines, hvlines);
// VLOG("HV-lines", hvlines);
//
Mat lines;
findLongLines(edges, lines, 15);
Mat w = Mat::ones(5,5,CV_8UC1);
dilate(lines, lines, w);
erode(lines, lines, w);
VLOG("Lines", lines);
Mat lines2;
Mat z = Mat::ones(2,2,CV_8UC1);
dilate(lines, lines, z);
findLongLines(lines, lines2, 30, 15);
//dilate(lines2, lines2, z);
//erode(lines2, lines2, z);
VLOG("Lines2", lines2);
Mat result = dark.clone();
//Mat copy = edges.clone();
//Mat copy = lines.clone();
Mat copy = lines2.clone();
vector > contours;
vector hierarchy;
findContours( copy, contours, hierarchy,
CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );
vector blobs;
Mat blank = dark.clone();
blank = 0.0;
Mat contour_shading = blank;//dark.clone();
for (vector >::iterator it = contours.begin();
it != contours.end(); ++it){
vector& contour = *it;
Rect r = boundingRect(Mat(contour));
double a1 = contourArea(Mat(contour));
double a2 = r.height * r.width;
if (a2 < 100)
continue;
if (abs(r.width - 65) > 5)
continue;
//if ( min(a1,a2)/max(a1,a2) > 0.80){
vector > cs;
cs.push_back(contour);
drawContours(contour_shading, cs, -1, Color::RANDOM(), CV_FILLED);
Blob blob(r);
blobs.push_back(blob);
//}
}
Mat contours_image = contour_shading*0.7 + dark*0.5;
Painter::drawBlobs(contours_image, blobs, Color::WHITE);
VLOG("ColoredSelectedContours", contours_image);
vector nonoverlapping_blobs;
// print output to stdout
for (vector::iterator it = blobs.begin();
it != blobs.end(); ++it){
Blob& b = *it;
bool not_overlap = true;
for (vector::iterator ito = nonoverlapping_blobs.begin();
ito != nonoverlapping_blobs.end(); ++ito){
Blob& bo = *ito;
not_overlap = b.x >= bo.x + bo.width || b.y >= bo.y + bo.height ||
b.x + b.width <= bo.x || b.y + b.height <= bo.y;
if (!not_overlap)
break;
}
if (not_overlap){
nonoverlapping_blobs.push_back(b);
}
}
vector& result_blobs = nonoverlapping_blobs
Mat blobs_result = dark.clone();
Painter::drawBlobs(blobs_result, result_blobs, Color::RED);
VLOG("OutputBlobs", blobs_result);
// print output to stdout
for (vector::iterator it = result_blobs.begin();
it != result_blobs.end(); ++it){
dout() << b.x << " " << b.y << " " << b.width << " " << b.height << endl;
}
return contours_image;
#endif
}
void
cvgui::findBoxes(const Mat& screen, vector& output_blobs){
Mat dark;
Util::rgb2grayC3(screen,dark);
dark = dark * 0.5;
VLOG("Input", screen);
Mat gray;
cvtColor(screen,gray,CV_RGB2GRAY);
//medianBlur(gray, gray, 3);
//VLOG("Blurred", gray);
Mat edges;
// Code for experimenting differenty parameters for Canny
// for (int c=10;c<=100;c=c+10){
// char buf[50];
// Mat test;
// sprintf(buf,"Canny%d",c);
// Canny(gray,test,0.66*c,1.33*c,3,true);
// VLOG(buf, test);
// }
int s = 100;
Canny(gray,edges,0.66*s,1.33*s,3,true);
VLOG("Canny", edges);
dilate(edges, edges, Mat::ones(2,2,CV_8UC1));
VLOG("Dilated", edges);
Mat result = dark.clone();
Mat copy = edges.clone();
vector > contours;
vector hierarchy;
findContours( copy, contours, hierarchy,
CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );
// findContours(edges, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
//findContours( copy, contours, hierarchy,
// CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );
// cout << contours.size() << " " << hierarchy.size() << endl;
// iterate through all the top-level contours,
// draw each connected component with its own random color
// int idx = 0;
// for( ; idx >= 0; idx = hierarchy[idx][0]){
//
// vector& contour = contours[idx];
//
//
// //Scalar color( rand()&255, rand()&255, rand()&255 );
// Scalar cyan(255,255,0);
// vector > cs;
// cs.push_back(contour);
// drawContours( result, cs, -1, cyan, 2);//, CV_FILLED);
//
// // drawContours( result, contours, idx, color, CV_FILLED, 8, hierarchy );
//
// }
vector blobs;
Mat box_contour_image = dark.clone();
for (vector >::iterator it = contours.begin();
it != contours.end(); ++it){
vector& contour = *it;
Rect r = boundingRect(Mat(contour));
double a1 = contourArea(Mat(contour));
double a2 = r.height * r.width;
if ( min(a1,a2)/max(a1,a2) > 0.80){
vector > cs;
cs.push_back(contour);
drawContours(box_contour_image, cs, -1, Color::RANDOM(), 2);//, CV_FILLED);
Blob blob(r);
blobs.push_back(blob);
}
}
VLOG("Box-shaped contours", box_contour_image);
Mat blobs_result = dark.clone();
Painter::drawBlobs(blobs_result, blobs, Color::RED);
VLOG("Blobs", blobs_result);
vector unique_blobs;
for (vector::iterator it = blobs.begin();
it != blobs.end(); ++it){
Blob& a = *it;
vector::iterator it1;
for (it1 = unique_blobs.begin();
it1 != unique_blobs.end(); ++it1){
Blob& b = *it1;
int d = 5;
bool similar_bounding_box =
abs(a.x-b.x) < d && abs(a.y-b.y) < d &&
abs(a.height-b.height) < 2*d &&
abs(a.width-b.width) < 2*d;
if (similar_bounding_box)
break;
}
// if no blob whose bounding box is similar
if (it1 == unique_blobs.end()){
// add this blob to the list of unique blobs
unique_blobs.push_back(a);
}
}
Mat unique_blobs_result = dark.clone();
Painter::drawBlobs(unique_blobs_result, unique_blobs, Color::RED);
VLOG("UniqueBlobs", unique_blobs_result);
vector leaf_blobs;
getLeafBlobs(unique_blobs, leaf_blobs);
Mat leaf_blobs_result = dark.clone();
Painter::drawBlobs(leaf_blobs_result, leaf_blobs, Color::RED);
VLOG("LeafBlobs", leaf_blobs_result);
output_blobs = leaf_blobs;
}
void
cvgui::computeUnitBlobs(const Mat& screen, Mat& output){
VLOG("Input", screen);
Mat gray;
cvtColor(screen,gray,CV_RGB2GRAY);
Mat edges;
Canny(gray,edges,0.66*50,1.33*50,3,true);
VLOG("Canny", edges);
// Mat corners;
// cornerHarris(gray,corners,10,5,1.0);
// Mat corners_result = screen.clone();
// vector corners;
// goodFeaturesToTrack(gray, corners, 50, 0.5, 10);
// for (vector::iterator it = corners.begin(); it != corners.end(); ++it){
// Point2f& p = *it;
// circle(corners_result, p, 3, Scalar(0,0,255));
// }
// VLOG("Corners", corners_result);
adaptiveThreshold(gray, gray, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY_INV, 5, 1);
VLOG("AdaptiveThresholded", gray);
Mat lines;
cvgui::findLongLines(gray, lines);
Mat lines_viz = lines.clone();
dilate(lines_viz, lines_viz, Mat::ones(4,4,CV_8UC1));
VLOG("LongLinesFound", lines_viz);
Mat not_lines;
bitwise_not(lines, not_lines);
Mat foreground;
bitwise_and(gray, not_lines, foreground);
gray.setTo(0, lines);
VLOG("LongLinesRemoved",gray);
dilate(edges, edges, Mat::ones(3,3,CV_8UC1));
bitwise_and(gray, edges, gray);
VLOG("NonEdgeRemoved", gray);
//GaussianBlur(gray, gray, Size(3, 3), 3);
//VLOG("Blurred", gray);
output = gray;
}
void
cvgui::getParagraphBlobs(const Mat& screen, vector& output_parablobs){
VisualLogger::newImage();
Mat screen_gray;
cvtColor(screen,screen_gray,CV_RGB2GRAY);
Mat blobs_mask;
cvgui::computeUnitBlobs(screen, blobs_mask);
Mat dark;
Util::rgb2grayC3(screen,dark);
dark = dark * 0.5;
vector blobs;
cvgui::extractBlobs(blobs_mask, blobs);
cvgui::calculateColor(blobs, screen, blobs_mask);
// draw blobs
Mat result_blobs = dark.clone();
Painter::drawBlobs(result_blobs, blobs, Scalar(255,255,0));
VLOG("blobs-extracted",result_blobs);
vector filtered_blobs;
for (vector::iterator it = blobs.begin();
it != blobs.end(); ++it){
Blob& blob = *it;
// if (blob.height < 3 && blob.width < 3)
// continue;
//
// if (blob.height < 4)
// continue;
filtered_blobs.push_back(blob);
}
Mat result_filtered_blobs = dark.clone();
Painter::drawBlobs(result_filtered_blobs, filtered_blobs, Scalar(255,255,0));
VLOG("blobs-filtered",result_filtered_blobs);
Mat result_lineblobs = dark.clone();
vector lineblobs;
cvgui::linkBlobsIntoLineBlobs(filtered_blobs, lineblobs, 20);
Painter::drawLineBlobs(result_lineblobs, lineblobs, Scalar(255,255,0));
VLOG("lineblobs", result_lineblobs);
Mat result_lineblobs_filtered = dark.clone();
vector filtered_lineblobs;
// Calculate the bounding rectangle of each line of linked blobs
for (vector::iterator it_lines = lineblobs.begin();
it_lines != lineblobs.end(); ++ it_lines){
LineBlob& line = *it_lines;
// Ignore lines with fewer than X elements
if (line.blobs.size()<2)
continue;
if (line.height < 3)
continue;
filtered_lineblobs.push_back(line);
}
Painter::drawLineBlobs(result_lineblobs_filtered, filtered_lineblobs, Scalar(255,255,0));
VLOG("lineblobs-filtered", result_lineblobs_filtered);
Mat result_merged_blobs = dark.clone();
vector merged_lineblobs;
cvgui::mergeLineBlobs(filtered_lineblobs, merged_lineblobs);
Painter::drawLineBlobs(result_merged_blobs, merged_lineblobs, Scalar(255,255,0));
VLOG("lineblobs-merged", result_merged_blobs);
vector parablobs;
cvgui::linkLineBlobsIntoPagagraphBlobs(merged_lineblobs, parablobs);
Mat result_linked_parablobs = dark.clone();
Painter::drawParagraphBlobs(result_linked_parablobs, parablobs, Scalar(255,0,0));
VLOG("paragblobs", result_linked_parablobs);
output_parablobs = parablobs;
// Mat screen_dark = screen * 0.2;
// Mat ocr_result_image = screen_dark;
//
//
// for (vector::iterator it = parablobs.begin();
// it != parablobs.end(); ++it){
//
//
// ParagraphBlob& parablob = *it;
//
// vector ocrlines;
//
// cvgui::run_ocr_on_lineblobs(parablob.lineblobs, screen_gray, ocrlines);
//
// Painter::drawOCRLines(ocr_result_image, ocrlines);
//
// }
//
// VLOG("OCR-Result", ocr_result_image);
}
void
cvgui::getLineBlobsAsIndividualWords(const Mat& screen, vector& output_lineblobs){
Mat screen_gray;
cvtColor(screen,screen_gray,CV_RGB2GRAY);
Mat blobs_mask;
cvgui::computeUnitBlobs(screen, blobs_mask);
Mat dark;
Util::rgb2grayC3(screen,dark);
dark = dark * 0.5;
vector blobs;
cvgui::extractBlobs(blobs_mask, blobs);
cvgui::calculateColor(blobs, screen, blobs_mask);
// draw blobs
Mat result_blobs = dark.clone();
Painter::drawBlobs(result_blobs, blobs, Scalar(255,255,0));
VLOG("blobs-extracted",result_blobs);
vector filtered_blobs;
for (vector::iterator it = blobs.begin();
it != blobs.end(); ++it){
Blob& blob = *it;
// if (blob.height < 3 && blob.width < 3)
// continue;
//
// if (blob.height < 4)
// continue;
filtered_blobs.push_back(blob);
}
Mat result_filtered_blobs = dark.clone();
Painter::drawBlobs(result_filtered_blobs, filtered_blobs, Scalar(255,255,0));
VLOG("blobs-filtered",result_filtered_blobs);
Mat result_lineblobs = dark.clone();
vector lineblobs;
cvgui::linkBlobsIntoLineBlobs(filtered_blobs, lineblobs, 3);
Painter::drawLineBlobs(result_lineblobs, lineblobs, Scalar(255,255,0));
VLOG("lineblobs", result_lineblobs);
Mat result_lineblobs_filtered = dark.clone();
vector filtered_lineblobs;
// Calculate the bounding rectangle of each line of linked blobs
for (vector::iterator it_lines = lineblobs.begin();
it_lines != lineblobs.end(); ++ it_lines){
LineBlob& line = *it_lines;
// Ignore lines with fewer than X elements
// if (line.blobs.size()<2)
// continue;
if (line.height < 3)
continue;
filtered_lineblobs.push_back(line);
}
Painter::drawLineBlobs(result_lineblobs_filtered, filtered_lineblobs, Scalar(255,255,0));
VLOG("lineblobs-filtered", result_lineblobs_filtered);
output_lineblobs = filtered_lineblobs;
// Mat result_merged_blobs = dark.clone();
//
// vector merged_lineblobs;
// cvgui::mergeLineBlobs(filtered_lineblobs, merged_lineblobs);
// Painter::drawLineBlobs(result_merged_blobs, merged_lineblobs, Scalar(255,255,0));
// VLOG("lineblobs-merged", result_merged_blobs);
//
//
// vector parablobs;
// cvgui::linkLineBlobsIntoPagagraphBlobs(merged_lineblobs, parablobs);
//
// Mat result_linked_parablobs = dark.clone();
//
// Painter::drawParagraphBlobs(result_linked_parablobs, parablobs, Scalar(255,0,0));
//
// VLOG("paragraph-linked", result_linked_parablobs);
//
//
// Mat screen_dark = screen * 0.2;
// Mat ocr_result_image = screen_dark;
//
//
// for (vector::iterator it = parablobs.begin();
// it != parablobs.end(); ++it){
//
//
// ParagraphBlob& parablob = *it;
//
// vector ocrlines;
//
// cvgui::run_ocr_on_lineblobs(parablob.lineblobs, screen_gray, ocrlines);
//
// Painter::drawOCRLines(ocr_result_image, ocrlines);
//
// }
//
// VLOG("OCR-Result", ocr_result_image);
}
/* not used currently
void
cvgui::segmentScreenshot(const Mat& screen, vector& text_blobs, vector& image_blobs){
VLOG("Input", screen);
Mat gray, screen_gray;
if(screen.channels() > 1){
cvtColor(screen,gray,CV_RGB2GRAY);
}
else
gray = screen;
screen_gray = gray.clone();
adaptiveThreshold(gray, gray, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY_INV, 5, 1);
VLOG("AdaptiveThresholded", gray);
Mat lines;
cvgui::findLongLines(gray, lines);
Mat lines_viz = lines.clone();
dilate(lines_viz, lines_viz, Mat::ones(4,4,CV_8UC1));
VLOG("LongLinesFound", lines_viz);
Mat not_lines;
bitwise_not(lines, not_lines);
Mat foreground;
bitwise_and(gray, not_lines, foreground);
gray.setTo(0, lines);
VLOG("LongLinesRemoved",gray);
denoise(gray);
VLOG("NoiseRemoved", gray);
dilate(gray,gray,Mat::ones(1,3,CV_8UC1));
VLOG("Dilated",gray);
vector rects;
//cvgui::extractRects(gray, rects);
vector blobs;
cvgui::extractBlobs(gray, blobs);
Mat dilated = gray.clone();
// visualization
Mat result;
Mat g;
cvtColor(screen, g, CV_RGB2GRAY);
Mat ss[3] = {g,g,g};
merge(ss,3,result);
result = result * 0.5;
Mat bg = result.clone();
Mat screen_darken = bg.clone();
text_blobs.clear();
for (vector::iterator b = blobs.begin(); b != blobs.end(); ++b){
Blob& blob = *b;
Rect& bound = blob;
Mat part(screen, bound);
//paste(part, result, r->x, r->y);
Mat p = part.clone();
Mat g;
cvtColor(p, g, CV_RGB2GRAY);
adaptiveThreshold(g, g, 255,
ADAPTIVE_THRESH_MEAN_C,
THRESH_BINARY_INV, 3, 1);
vector rs;
cvgui::extractSmallRects(g, rs);
for (vector::iterator r = rs.begin();r != rs.end(); ++r){
r->x += bound.x;
r->y += bound.y;
}
vector rs0;
for (vector::iterator q = rs.begin();
q != rs.end(); ++q){
// exclude overly short element (e.g., dot of i)
if (q->height < 5)
continue;
rs0.push_back(*q);
}
rs = rs0;
// re-calculate the bounds
int x1,y1,x2,y2;
x1 = bound.x + bound.width;
y1 = bound.y + bound.height;
x2 = bound.x;
y2 = bound.y;
for (vector::iterator r = rs.begin();
r != rs.end(); ++r){
x1 = min(x1, r->x);
y1 = min(y1, r->y);
x2 = max(x2, r->x + r->width);
y2 = max(y2, r->y + r->height);
}
//blob.bound = Rect(x1-2,y1-2,x2-x1+4,y2-y1+4);
//blob.bound = Rect(x1,y1,x2-x1,y2-y1);
// make the bound bigger to be consistent with the dilated blobs
blob = Blob(Rect(x1-2,y1-1,x2-x1+4,y2-y1+2));
int MINIMUM_NUM_CHARBLOBS = 2;
if (cvgui::areHorizontallyAligned(rs) && rs.size()>=MINIMUM_NUM_CHARBLOBS)
Painter::drawRects(result, rs, Scalar(0,255,0));
else
Painter::drawRects(result, rs, Scalar(0,0,255));
if (cvgui::areHorizontallyAligned(rs) && rs.size()>=MINIMUM_NUM_CHARBLOBS){
text_blobs.push_back(blob);
}
}
//drawRects(result, rects, Scalar(255,0,0));
Painter::drawBlobs(result, blobs, Scalar(255,0,0));
VLOG("TextBlocksExtracted",result);
Mat text_mask = Mat::zeros(screen.size(), CV_8UC1);
for (vector::iterator b = text_blobs.begin();
b != text_blobs.end(); ++b){
Rect& r = *b;
Mat m(text_mask,
Range(r.y,r.y+r.height),
Range(r.x,r.x+r.width));
m = 255;
}
VLOG("TextBinaryMaskComputed", text_mask);
gray.setTo(0, text_mask);
VLOG("AfterTextRemoved",gray);
dilate(gray,gray,Mat());
VLOG("DilatedAgain",gray);
Mat dilated_again = gray.clone();
vector temp;
//cvgui::extractRects(gray, temp);
cvgui::extractBlobs(gray, temp);
// only keep image rects larger than n pixels
const int MIN_IMAGE_RECT_AREA = 150;
image_blobs.clear();
for (vector::iterator b = temp.begin();
b != temp.end(); ++b){
if (b->width * b->height < MIN_IMAGE_RECT_AREA)
continue;
// // blob is too big, something is wrong
// if (b->bound.width > 0.8 * screen.width)
// continue;
// if (b->bound.height > 0.8 * screen.height)
// continue;
image_blobs.push_back(*b);
}
Mat image_result = bg.clone();
Painter::drawBlobs(image_result, image_blobs, Scalar(0,0,255));
VLOG("ImageRecordsExtracted", image_result);
return;
Mat ui_mask = Mat::zeros(screen.size(), CV_8UC1);
Mat photo_mask = Mat::zeros(screen.size(), CV_8UC1);
for (vector::iterator b = image_blobs.begin();
b != image_blobs.end(); ++b){
Rect& r = *b;
Mat mask;
if (r.height < 100)
mask = ui_mask;
else
mask = photo_mask;
Mat m(mask,
Range(r.y,r.y+r.height),
Range(r.x,r.x+r.width));
m = 255;
}
VLOG("UIMask", ui_mask);
VLOG("PhotoMask", photo_mask);
Mat segmap;
Mat segmapr;
Mat segmapg;
Mat segmapb;
bitwise_and(dilated,text_mask,segmapr);
bitwise_and(dilated,ui_mask,segmapg);
bitwise_and(dilated_again,photo_mask,segmapb);
//segmapb = photo_mask;
Mat cs[3] = {segmapb, segmapg,segmapr};
merge(cs,3,segmap);
VLOG("SegMap", segmap);
//Mat wordmap = screen_darken.clone();//segmap.clone();
Mat wordmap = Mat::zeros(screen.size(), CV_8UC3);
screen.copyTo(wordmap, segmapg);
screen.copyTo(wordmap, photo_mask);
screen.copyTo(wordmap, text_mask);
Mat random_ids = Mat::ones(1,100,CV_8UC1);
randu(random_ids, 22, 80);
Scalar white(255,255,255);
Scalar black(0,0,0);
Scalar yellow(255,255,0);
int i = 0;
for (vector::iterator b = image_blobs.begin();
b != image_blobs.end(); ++b){
Rect& r = *b;
char vwstr[100];
if (r.height < 100){
int xc = r.x + r.width/2;
int yc = r.y + r.height/2;
// putTextWithBackgroundCentered(black, wordmap, "u12", Point(xc,yc),
// FONT_HERSHEY_SIMPLEX, 0.5, white);
int id = random_ids.at(0,i++);
sprintf(vwstr,"u%d",id);
// putTextWithBackgroundCentered(white, wordmap, vwstr, Point(xc,yc),
// FONT_HERSHEY_DUPLEX, 0.5, black);
}else{
//TODO SURF surf_extractor(6.0e3);
vector keypoints;
// printf("Extracting keypoints\n");
//TODO surf_extractor(screen_gray, photo_mask, keypoints);
//printf("Extracted %d keypoints from the image\n", (int)keypoints.size());
for (vector::iterator it = keypoints.begin(); it != keypoints.end(); ++it){
KeyPoint& p = *it;
circle(wordmap, p.pt, p.size*1.5, yellow);
// putTextWithBackgroundCentered(black, wordmap, "v12", p.pt,
// FONT_HERSHEY_SIMPLEX, 0.5, white);
int id = random_ids.at(0,i++);
sprintf(vwstr,"s%d",id);
// putTextWithBackgroundCentered(white, wordmap, vwstr, p.pt,
// FONT_HERSHEY_DUPLEX, 0.5, black);
}
}
}
VLOG("WordMap", wordmap);
}
*/
static int L1dist(Vec3b p1, Vec3b p2){
return max(p1[0],p2[0])-min(p1[0],p2[0])+
max(p1[1],p2[1])-min(p1[1],p2[1])+
max(p1[2],p2[2])-min(p1[2],p2[2]);
}
bool
cvgui::areHorizontallyAligned(const vector& rects){
if (rects.size() <= 1)
return true;
vector sorted_rects = rects;
sort(sorted_rects, sort_by_x);
int ymin = 10000;
int ymax = 0;
bool no_overlap = true;
for (vector::const_iterator r = sorted_rects.begin() + 1;
r != sorted_rects.end(); ++r){
no_overlap = no_overlap && (r->x >= (r-1)->x + (r-1)->width - 2);
int baseline = r->y + r->height;
ymin = min(baseline, ymin);
ymax = max(baseline, ymax);
}
bool baseline_aligned = (ymax - ymin < 10);
int minv = 10000;
int maxv = 0;
for (vector::const_iterator r = sorted_rects.begin();
r != sorted_rects.end(); ++r){
int v = r->height;
minv = min(v, minv);
maxv = max(v, maxv);
}
bool height_similar = (maxv - minv < 10);
// if the difference between the highest and lowest baseline
// is too large, it means the rects are not alginged horizontally
return baseline_aligned && height_similar && no_overlap;
}
bool
cvgui::hasMoreThanNUniqueColors(const Mat& src, int n){
Mat_::const_iterator it = src.begin(),
itEnd = src.end();
vector< pair > colors;
//vector counts;
colors.push_back( pair(*it,1) );
++it;
for(; it != itEnd; ++it){
bool matched;
matched = false;
for (vector< pair >::iterator c = colors.begin();
c != colors.end();
++c){
Vec3b& color = (*c).first;
int& count = (*c).second;
int d = L1dist((*it), (color));
//cout << d << endl;
if (d < 150){
matched = true;
count++;
break;
}
}
if (!matched){
// if (colors.size() == 4)
// return true;
// else
colors.push_back(pair(*it,1));
}
}
dout() << endl << endl;
for (vector< pair >::iterator c = colors.begin();
c != colors.end();
++c){
Vec3b& color = (*c).first;
int& count = (*c).second;
//cout << count << endl;
}
return (colors.size() > 5);
}
void
cvgui::extractSmallRects(const Mat& src,
vector& rects){
Mat copy = src.clone();
vector > contours;
findContours(copy, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
for (vector >::iterator contour = contours.begin();
contour != contours.end(); ++contour){
Rect bound = boundingRect(Mat(*contour));
rects.push_back(bound);
}
}
void
cvgui::calculateColor(vector& blobs,
const Mat& color_image,
const Mat& foreground_mask){
for (vector::iterator it = blobs.begin();
it != blobs.end(); ++it){
Blob& blob = *it;
Mat part(color_image, blob);
Mat mask(foreground_mask, blob);
Scalar mean, stddev;
meanStdDev(part, mean, stddev, mask);
blob.mr = mean[0];
blob.mg = mean[1];
blob.mb = mean[2];
}
}
void
cvgui::extractBlobs(const Mat& src, vector& blobs){
Mat copy = src.clone();
blobs.clear();
vector > contours;
findContours(copy, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
for (vector >::iterator contour = contours.begin();
contour != contours.end(); ++contour){
double area = contourArea(Mat(*contour));
Rect bound = boundingRect(Mat(*contour));
Blob blob(bound);
blob.area = area;
blobs.push_back(blob);
}
}
void
cvgui::extractRects(const Mat& src,
vector& rects){
Mat copy = src.clone();
rects.clear();
vector > contours;
findContours(copy, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
for (vector >::iterator contour = contours.begin();
contour != contours.end(); ++contour){
double area = contourArea(Mat(*contour));
Rect bound = boundingRect(Mat(*contour));
// too small
if (bound.width < 6 || bound.height < 6)
continue;
// too empty
if (bound.height > 100 && bound.width * bound.height * 0.50 > area)
continue;
rects.push_back(bound);
}
}
void
cvgui::findLongLines_Vertical(const Mat& src, Mat& dest, int min_length, int extension){
dest = src.clone();
Mat maskT, destT;
transpose(dest,destT);
cvgui::findLongLines_Horizontal(destT,maskT,min_length, extension);
Mat maskTT;
transpose(maskT,maskTT);
dest = maskTT;
}
void
cvgui::findLongLines(const Mat& src, Mat& dest, int min_length, int extension){
Mat copy = src.clone();
Mat v,h;
cvgui::findLongLines_Horizontal(copy, h, min_length, extension);
cvgui::findLongLines_Vertical(copy, v, min_length, extension);
// Mat maskT, destT;
// transpose(dest,destT);
// cvgui::findLongLines_Horizontal(destT,maskT,min_length, extension);
//
// Mat maskTT;
// transpose(maskT,maskTT);
bitwise_or(v,h,dest);
}
//void
//cvgui::filterLineSegments(const Mat& src, Mat& dest,
// int min_length, int max_length){
//
// typedef uchar T;
//
// int extension = 5;
//
// dest = Mat::zeros(src.rows,src.cols,CV_8UC1);
//
// Size size = src.size();
// for( int i = 0; i < size.height; i +=1 ){
//
// const T* ptr1 = src.ptr(i);
// T* ptr2 = dest.ptr(i);
//
// bool has_previous_baseline = false;
// int previous_baseline_endpoint = 0;
// int current_baseline_startpoint = 0;
//
//
// for( int j = 1; j < size.width; j += 1 ){
//
//
// if (ptr1[j] > 0 && ptr1[j-1] == 0){
// current_baseline_startpoint = j;
// }
//
// if (ptr1[j-1] > 0 && (ptr1[j] == 0 || j == size.width - 1)){
//
//
// // check for the condition of a baseline hypothesis
// // the length of the baseline must be > 15
// if ((j - current_baseline_startpoint) > min_length){// || j == size.width - 1){
//
// // int closeness_threshold = 1;
// // if (has_previous_baseline &&
// // (current_baseline_startpoint - previous_baseline_endpoint)
// // <= closeness_threshold){
// //
// //
// // // merge the current baseline with the previously baseline
// // for (int k=previous_baseline_endpoint;
// // k < current_baseline_startpoint; k += 1){
// // ptr2[k] = ptr1[j];
// // }
// // }
//
// // has_previous_baseline = true;
// //previous_baseline_endpoint = j;
//
//
// for (int k=current_baseline_startpoint; k < j; ++k){
// ptr2[k] = 255;
// }
//
// for (int k=j; k < min(j+extension,size.width-1); ++k){
// ptr2[k] = 255;
// }
//
//
// }
//
// // forming a new baseline hypothesis
// //current_baseline_startpoint = j+1;
// }
// }
// }
//
//}
void
cvgui::voteCenter_Vertical(const Mat& binary, Mat& dest,
int min_length, int tolerance, int distance){
dest = binary.clone();
Mat maskT, destT;
transpose(dest,destT);
cvgui::voteCenter_Horizontal(destT,maskT,min_length,tolerance,distance);
Mat maskTT;
transpose(maskT,maskTT);
dest = maskTT;
}
void
cvgui::voteCenter_Horizontal(const Mat& binary, Mat& dest,
int min_length, int tolerance, int distance){
typedef uchar T;
dest = Mat::zeros(binary.rows,binary.cols,CV_8UC1);
Size size = binary.size();
for( int i = 0; i < size.height; i +=1 ){
const T* ptr1 = binary.ptr(i);
T* ptr2 = 0;
//dest.ptr(i);
//
//
// T* ptru = 0;
// T* ptrb = 0;
//
int grid = 5;
int gi = grid*(i+distance)/grid;
if (gi >= 0 && gi < size.height){
ptr2 = dest.ptr(i+distance);
}
// if (grid*(i+distance)/grid(i+distance);
// }
bool has_previous_baseline = false;
int previous_baseline_endpoint = 0;
int current_baseline_startpoint = 0;
for( int j = 1; j < size.width; j += 1 ){
if (ptr1[j] > 0 && ptr1[j-1] == 0){
current_baseline_startpoint = j;
}
if (ptr1[j-1] > 0 && (ptr1[j] == 0 || j == size.width - 1)){
// check for the condition of a baseline hypothesis
// the length of the baseline must be > 15
if ((j - current_baseline_startpoint) > min_length){// || j == size.width - 1){
for (int k=current_baseline_startpoint+min_length/2; k < j-min_length/2; ++k){
if (ptr2)
ptr2[k] = 255;
}
for (int k=j-min_length/2; k < min(j-min_length/2+tolerance,size.width-1); ++k){
if (ptr2)
ptr2[k] = 255;
}
}
// forming a new baseline hypothesis
//current_baseline_startpoint = j+1;
}
}
}
}
void
cvgui::findLongLines_Horizontal(const Mat& binary, Mat& dest,
int min_length, int extension){
typedef uchar T;
dest = Mat::zeros(binary.rows,binary.cols,CV_8UC1);
Size size = binary.size();
for( int i = 0; i < size.height; i +=1 ){
const T* ptr1 = binary.ptr(i);
T* ptr2 = dest.ptr(i);
bool has_previous_baseline = false;
int previous_baseline_endpoint = 0;
int current_baseline_startpoint = 0;
for( int j = 1; j < size.width; j += 1 ){
if (ptr1[j] > 0 && ptr1[j-1] == 0){
current_baseline_startpoint = j;
}
if (ptr1[j-1] > 0 && (ptr1[j] == 0 || j == size.width - 1)){
// check for the condition of a baseline hypothesis
// the length of the baseline must be > 15
if ((j - current_baseline_startpoint) > min_length){// || j == size.width - 1){
// int closeness_threshold = 1;
// if (has_previous_baseline &&
// (current_baseline_startpoint - previous_baseline_endpoint)
// <= closeness_threshold){
//
//
// // merge the current baseline with the previously baseline
// for (int k=previous_baseline_endpoint;
// k < current_baseline_startpoint; k += 1){
// ptr2[k] = ptr1[j];
// }
// }
// has_previous_baseline = true;
//previous_baseline_endpoint = j;
for (int k=current_baseline_startpoint; k < j; ++k){
ptr2[k] = 255;
}
for (int k=j; k < min(j+extension,size.width-1); ++k){
ptr2[k] = 255;
}
}
// forming a new baseline hypothesis
//current_baseline_startpoint = j+1;
}
}
}
}
Mat
cvgui::obtainGrayBackgroundMask(const Mat& input){
Mat copy = input.clone();
Mat_::iterator it = copy.begin(),
itEnd = copy.end();
for(; it != itEnd; ++it){
uchar& b = (*it)[0];
uchar& g = (*it)[1];
uchar& r = (*it)[2];
if (r == 0 && b == 0 && g == 0){
r = 1; b = 1; g = 1;
}
if (b > 50 &&
abs(b-g) < 10 && abs(g-b) < 10 && abs(b-r) < 10){
r = 0;
g = 0;
b = 0;
}
}
Mat ms[3];
split(copy, ms);
Mat mask;
threshold(ms[0],mask,0,255,THRESH_BINARY);
dilate(mask,mask,Mat());
return mask;
}
Mat
cvgui::removeGrayBackground(const Mat& input){
// Mat copy = input.clone();
// Mat mask;
// // (Size(copy.rows,copy.cols), CV_8UC1);
//
// Mat_::iterator it = copy.begin(),
// itEnd = copy.end();
// for(; it != itEnd; ++it){
//
// uchar& b = (*it)[0];
// uchar& g = (*it)[1];
// uchar& r = (*it)[2];
//
// if (r == 0 && b == 0 && g == 0){
// r = 1; b = 1; g = 1;
// }
//
// if (b > 50 &&
// abs(b-g) < 10 && abs(g-b) < 10 && abs(b-r) < 10){
// r = 0;
// g = 0;
// b = 0;
// }
//
//
//
// }
//
//
// Mat ms[3];
// split(copy, ms);
//
// //threshold(ms[0],mask,0,255,THRESH_BINARY_INV);
// threshold(ms[0],mask,0,255,THRESH_BINARY);
//
// dilate(mask,mask,Mat());
//
//
// vector > contours;
// findContours(ms[0], contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
//
// Scalar red(0,0,255);
// //drawContours(copy, contours, -1, red);
//
//
// vector boundingRects;
//
// for (vector >::iterator contour = contours.begin();
// contour != contours.end(); ++contour){
//
//
// double area = contourArea(Mat(*contour));
//
// Rect bound = boundingRect(Mat(*contour));
//
//
// if (bound.width * bound.height * 0.5 > area)
// continue;
//
// boundingRects.push_back(bound);
//
// rectangle(copy,
// Point(bound.x, bound.y),
// Point(bound.x + bound.width, bound.y + bound.height),
// red);
//
// cout << bound.x << "," << bound.y << endl;
//
// }
//
//
//
// Mat result(Size(input.cols,input.rows), CV_8UC3);
// for (vector::iterator bound = boundingRects.begin();
// bound != boundingRects.end(); ++bound){
//
// if (bound->width < 10 || bound->height < 8)
// continue;
//
// Mat r(input, *bound);
// paste(r, result, bound->x, bound->y);
//
//
// }
//
//
// namedWindow("result",1);
// imshow("result",result);
//
//
// namedWindow("copy",1);
// imshow("copy",copy);
//
// namedWindow("mask",1);
// imshow("mask",mask);
// waitKey(0);
return Mat();
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy