Better separation of code: analysis / dewarp
this is good both for code cleanness and for better performance analysis
This commit is contained in:
parent
45115fce04
commit
257b569d8d
1 changed files with 78 additions and 61 deletions
139
lines.cpp
139
lines.cpp
|
@ -107,25 +107,55 @@ bool Options::parse(int argc, char *argv[])
|
|||
return false;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
class BookShape {
|
||||
private:
|
||||
cv::Mat trasf[2];
|
||||
void precompute();
|
||||
cv::Point2f trapezoids[2][4]; //transformation matrix
|
||||
public:
|
||||
BookShape(cv::Point tl, cv::Point tm, cv::Point tf,
|
||||
cv::Point bl, cv::Point bm, cv::Point br);
|
||||
double xsize();
|
||||
double ysize();
|
||||
cv::Mat* getTrasfs();
|
||||
};
|
||||
BookShape::BookShape(cv::Point tl, cv::Point tm, cv::Point tr, cv::Point bl, cv::Point bm, cv::Point br)
|
||||
{
|
||||
Options args;
|
||||
try{
|
||||
if(args.parse(argc, argv)) {
|
||||
usage(argv[0], std::cout);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
} catch(std::runtime_error) {
|
||||
usage(argv[0], std::cerr);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
trapezoids[0][0] = tl;
|
||||
trapezoids[0][1] = tm;
|
||||
trapezoids[0][2] = bm;
|
||||
trapezoids[0][3] = bl;
|
||||
trapezoids[1][0] = tm;
|
||||
trapezoids[1][1] = tr;
|
||||
trapezoids[1][2] = br;
|
||||
trapezoids[1][3] = bm;
|
||||
precompute();
|
||||
}
|
||||
|
||||
cv::Mat img;
|
||||
img=cv::imread(args.input,CV_LOAD_IMAGE_GRAYSCALE);
|
||||
if( img.empty() ) {
|
||||
std::cerr << "Error opening image, aborting" << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
void BookShape::precompute(void) {
|
||||
cv::Point2f outsizes[4] = {cv::Point2f(0, 0), cv::Point(xsize(), 0),
|
||||
cv::Point(xsize(), ysize()), cv::Point(0, ysize())};
|
||||
for(int i=0; i < 2; i++) {
|
||||
trasf[i] = cv::getPerspectiveTransform(trapezoids[i], outsizes);
|
||||
assert(9==trasf[i].total()); // 3x3
|
||||
}
|
||||
}
|
||||
cv::Mat* BookShape::getTrasfs()
|
||||
{
|
||||
return trasf;
|
||||
}
|
||||
double BookShape::xsize()
|
||||
{
|
||||
return dist(trapezoids[0][0], trapezoids[0][1]);
|
||||
}
|
||||
double BookShape::ysize()
|
||||
{
|
||||
return dist(trapezoids[0][1], trapezoids[0][2]);
|
||||
}
|
||||
|
||||
|
||||
BookShape get_book_shape(cv::Mat img)
|
||||
{
|
||||
//dotwidth is just a simple size so that lines and dots are visible on big images
|
||||
//but not huge on small images
|
||||
#ifdef _DEBUG
|
||||
|
@ -139,7 +169,7 @@ int main(int argc, char *argv[])
|
|||
|
||||
if( 0==contours.size() ) {
|
||||
std::cerr << "No contours found" << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
throw "Error getting contours";
|
||||
}
|
||||
auto contour = contours[0];
|
||||
if( 1!=contours.size() )
|
||||
|
@ -165,15 +195,6 @@ int main(int argc, char *argv[])
|
|||
corn_3 = hull[maxdistances[1]];
|
||||
corn_4 = hull[(maxdistances[1]+1)%hull.size()];
|
||||
|
||||
#ifdef _DEBUG
|
||||
img = cv::imread(args.input,CV_LOAD_IMAGE_COLOR); // uncomment to this to display image with colors
|
||||
std::cout << "Maxdist1:" << maxdistances[0] << " " << corn_1 << corn_2 << std::endl;
|
||||
std::cout << "Maxdist2:" << maxdistances[1] << " " << corn_3 << corn_4 << std::endl;
|
||||
cv::namedWindow("win", CV_GUI_NORMAL);
|
||||
// cv::imshow("4 corners",img);
|
||||
// cv::waitKey(0);
|
||||
#endif
|
||||
|
||||
std::vector<cv::Point> verticals[2];
|
||||
// Between the two corners on the same side, the longest line is the vertical border of the book
|
||||
verticals[0] = find_longest_line(hull, (maxdistances[0]+1)%hull.size(), maxdistances[1]);
|
||||
|
@ -214,24 +235,33 @@ int main(int argc, char *argv[])
|
|||
cv::Point middle1 = further_point_from_line(get_line(corn_1, corn_2), points2);
|
||||
cv::Point middle2 = further_point_from_line(get_line(corn_3, corn_4), points1);
|
||||
|
||||
// we now have all the points of the two trapezoid (middle1 and middle2 are shared)
|
||||
cv::Mat trasf[2]; //transformation matrix
|
||||
double xsize = dist(corn_1, middle1), ysize=dist(middle1, middle2);
|
||||
cv::Point2f trapezoid[2][4] = {
|
||||
{corn_1, middle1, middle2, corn_4},
|
||||
{corn_2, corn_3, middle2, middle1}};
|
||||
cv::Point2f outsizes[4] = {cv::Point2f(0, 0), cv::Point(xsize, 0),
|
||||
cv::Point(xsize, ysize), cv::Point(0, ysize)};
|
||||
cv::Mat rect[2]; //final pages, transformed in a nice rectangle
|
||||
BookShape bs = BookShape(
|
||||
corn_1, middle1, corn_2,
|
||||
corn_4, middle2, corn_3);
|
||||
return bs;
|
||||
}
|
||||
|
||||
//we are rereading in full color to get colored output
|
||||
img = cv::imread(args.input,CV_LOAD_IMAGE_COLOR);
|
||||
for(int i=0; i < 2; i++) {
|
||||
trasf[i] = cv::getPerspectiveTransform(trapezoid[i], outsizes);
|
||||
assert(9==trasf[i].total()); // 3x3
|
||||
cv::warpPerspective(img, rect[i], trasf[i], cv::Size(xsize, ysize));
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
Options args;
|
||||
try{
|
||||
if(args.parse(argc, argv)) {
|
||||
usage(argv[0], std::cout);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
} catch(std::runtime_error) {
|
||||
usage(argv[0], std::cerr);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
cv::Mat img;
|
||||
img=cv::imread(args.input,CV_LOAD_IMAGE_GRAYSCALE);
|
||||
if( img.empty() ) {
|
||||
std::cerr << "Error opening image, aborting" << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
BookShape bs = get_book_shape(img);
|
||||
|
||||
if(args.profile) {
|
||||
// format: each line is a tab-delimited 3x3 transformation matrix (as get by getPerspectiveTransform)
|
||||
// first three elements is the first line, etc
|
||||
|
@ -239,7 +269,7 @@ int main(int argc, char *argv[])
|
|||
profilebuf.open(args.profile);
|
||||
for(int t=0; t<2; t++) {
|
||||
for(int i=0; i<3; i++) {
|
||||
double* row= trasf[t].ptr<double>(i);
|
||||
double* row= bs.getTrasfs()[t].ptr<double>(i);
|
||||
for(int j=0; j < 3; j++) {
|
||||
profilebuf << std::fixed << std::setprecision(16);
|
||||
profilebuf << row[j] << "\t"; //yes, there's a trailing tab
|
||||
|
@ -250,34 +280,21 @@ int main(int argc, char *argv[])
|
|||
profilebuf.close();
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
cv::line(img, corn_1, middle1, MAGENTA, dotwidth>>3);
|
||||
cv::line(img, corn_2, middle1, MAGENTA, dotwidth>>3);
|
||||
cv::line(img, middle1, middle2, BLACK, dotwidth>>4);
|
||||
cv::line(img, corn_3, middle2, MAGENTA, dotwidth>>3);
|
||||
cv::line(img, corn_4, middle2, MAGENTA, dotwidth>>3);
|
||||
cv::line(img, corn_2, corn_3, BLUE, dotwidth>>4);
|
||||
cv::line(img, corn_1, corn_4, BLUE, dotwidth>>4);
|
||||
std::cout << middle1 << middle2 << std::endl;
|
||||
|
||||
cv::imshow("win",img);
|
||||
while(1)
|
||||
{
|
||||
if( (char)cv::waitKey(0) == 113 )
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//TODO: distinguish left and right
|
||||
std::vector<int> params;
|
||||
if(args.left || args.right) {
|
||||
//we are rereading in full color to get colored output
|
||||
img = cv::imread(args.input,CV_LOAD_IMAGE_COLOR);
|
||||
cv::Mat rect[2]; //final pages, transformed in a nice rectangle
|
||||
|
||||
params.push_back(CV_IMWRITE_PNG_COMPRESSION);
|
||||
params.push_back(9);
|
||||
if(args.left) {
|
||||
cv::warpPerspective(img, rect[0], bs.getTrasfs()[0], cv::Size(bs.xsize(), bs.ysize()));
|
||||
cv::imwrite(args.left, rect[0], params);
|
||||
}
|
||||
if(args.right) {
|
||||
cv::warpPerspective(img, rect[1], bs.getTrasfs()[1], cv::Size(bs.xsize(), bs.ysize()));
|
||||
cv::imwrite(args.right, rect[1], params);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue