
srcnativelibs.Vision.cvgui.cpp Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of sikulixlibslux Show documentation
Show all versions of sikulixlibslux Show documentation
... for visual testing and automation (Linux native support)
The newest version!
/*
* Copyright 2010-2016, 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