Closed zvezdochiot closed 3 years ago
Hi @ksharindam .
Working scheme:
That is difficult to do. Because this requires mapping many points and creating a matrix and then solving that. And I have very poor knowledge in linear algebra. For avoiding matrix algebra, I used Qt's quadToQuad() function, but in this case It can not be used.
Hi @ksharindam .
Linear algebra is unnecessary. You need to apply to each quadrilateral (green) Un-tilt into a rectangle (blue), and then "sew" the rectangles.
Initial grid (blue) - uniform, set by parameters M and N. The extreme nodes cannot be touched, only the central ones.
RESTRICTION: A node cannot go past the next node.
Hi @ksharindam .
Meshing and manipulating with it is a problem for me. Therefore, I switched to considering Warp (coordinate displacement) in the form of a sum of displacement vectors:
dv{x,y} = v.{x,y}2 - v.{x,y}1
L2v = dvx * dvx + dvy * dvy
d{x,y} = p.{x,y} - v.{x,y}1
L2 = dx * dx + dy * dy
w = 1.0 / (1.0 + L2 / L2v)
dp{x,y} = dv{x,y} * w
dps{x,y} = sum(dp{x,y}, {v}) / sum(w, {v})
dpc{x,y} = sum(dv{x,y}. {v}) / count({v})
p.{x,y} += (dps{x,y} - dpc{x,y})
Any ideas how to organize the offset vectors?
Hi @ksharindam .
I study https://github.com/winddyhe/imagedigitizer how the most suitable one. Maybe there is something closer?
Hi @ksharindam .
Maybe use mask for horizontal warping?
Then the two halves of the image are easily transformed by stretching along the columns to the centerline.
See also #30 .
PS: The middle line is determined by either the upper or the lower area: xm = height - area_h / width = area_d /width
.
I have no idea how to do this. Previously created mask can not be applied after a transformation.
@ksharindam say:
I have no idea how to do this.
❓ Is it possible in Qt to somehow draw broken upper and lower lines with the condition x[i + 1]> x[i]
? I just need this. I know what to do with them.
🔓 Give me an interface without action (empty action), and the transformation is mine.
Hi @ksharindam .
Dewapring requires:
Dialog:
Two lines of N nodes:
I still have no idea how to do it. Did you find a way to do it?
Hi @ksharindam .
While I think. My GUI is bad.
Hi @ksharindam .
Now I'm playing with the patch:
diff -Nard photoquick-4.3.8-orig/src/transform.cpp photoquick-4.3.8-temp/src/transform.cpp
358,361c358,367
< p1 = topleft = QPoint(0,0);
< p2 = topright = QPoint(pixmap.width()-1, 0);
< p3 = btmleft = QPoint(0, pixmap.height()-1);
< p4 = btmright = QPoint(pixmap.width()-1, pixmap.height()-1);
---
> int i, sx = 1, sy = 1, st, xt, yt;
> for (i = 0; i < 4; i++)
> {
> xt = (sx < 0) ? (pixmap.width() - 1) : 0;
> yt = (sy < 0) ? (pixmap.height() - 1) : 0;
> p[i] = pt[i] = QPoint(xt, yt);
> st = sx;
> sx = -sy; //1, -1, -1, 1
> sy = st; //1, 1, -1, -1
> }
383,392c389,398
< if (QRect(topleft, QSize(60, 60)).contains(clk_pos))
< clk_area = 1; // Topleft is clicked
< else if (QRect(topright, QSize(-60, 60)).contains(clk_pos))
< clk_area = 2; // Topright is clicked
< else if (QRect(btmleft, QSize(60, -60)).contains(clk_pos))
< clk_area = 3; // Bottomleft is clicked
< else if (QRect(btmright, QSize(-60, -60)).contains(clk_pos))
< clk_area = 4; // bottom right corner clicked
< else
< clk_area = 0;
---
> clk_area = 0;
> int i, sx = 1, sy = 1, st;
> for (i = 0; i < 4; i++)
> {
> if (QRect(pt[i], QSize(sx * 60, sy * 60)).contains(clk_pos))
> clk_area = i + 1;
> st = sx;
> sx = -sy; //1, -1, -1, 1
> sy = st; //1, 1, -1, -1
> }
399,402c405,406
< topleft = p1;
< topright = p2;
< btmleft = p3;
< btmright = p4;
---
> for (int i = 0; i < 4; i++)
> pt[i] = p[i];
412,434c416,419
< switch (clk_area) {
< case 1 : { // Top left corner is clicked
< new_pt = topleft + moved;
< p1 = QPoint(MAX(0, new_pt.x()), MAX(0, new_pt.y()));
< break;
< }
< case 2 : { // Top right corner is clicked
< new_pt = topright + moved;
< p2 = QPoint(MIN(last_pt.x(), new_pt.x()), MAX(0, new_pt.y()));
< break;
< }
< case 3 : { // Bottom left corner is clicked
< new_pt = btmleft + moved;
< p3 = QPoint(MAX(0, new_pt.x()), MIN(last_pt.y(), new_pt.y()));
< break;
< }
< case 4 : { // Bottom right corner is clicked
< QPoint new_pt = btmright + moved;
< p4 = QPoint(MIN(last_pt.x(), new_pt.x()), MIN(last_pt.y(), new_pt.y()));
< break;
< }
< default:
< break;
---
> if (clk_area > 0)
> {
> new_pt = pt[clk_area - 1] + moved;
> p[clk_area - 1] = QPoint(MIN(last_pt.x(), MAX(0, new_pt.x())), MIN(last_pt.y(), MAX(0, new_pt.y())));
445c430
< polygon << p1<< p2<< p4<< p3;
---
> polygon << p[0] << p[1] << p[2] << p[3];
448,455c433,443
< calcArc(p1, p2, p3, p4, start, span);
< painter.drawArc(p1.x()-30, p1.y()-30, 60,60, 16*start, 16*span);
< calcArc(p2, p1, p4, p3, start, span);
< painter.drawArc(p2.x()-30, p2.y()-30, 60,60, 16*start, 16*span);
< calcArc(p3, p4, p1, p2, start, span);
< painter.drawArc(p3.x()-30, p3.y()-30, 60,60, 16*start, 16*span);
< calcArc(p4, p2, p3, p1, start, span);
< painter.drawArc(p4.x()-30, p4.y()-30, 60,60, 16*start, 16*span);
---
> int i, j0, j1, j2, j3;
> for (i = 0; i < 4; i++)
> {
> j0 = i;
> j3 = (i + 2) % 4;
> j1 = ((i - 1) < 0) ? (1 - i) : (i - 1);
> j2 = (j1 + 2) % 4;
>
> calcArc(p[j0], p[j1], p[j2], p[j3], start, span);
> painter.drawArc(p[i].x() - 30, p[i].y() - 30, 60, 60, 16 * start, 16 * span);
> }
458c446
< polygon<< p1+QPoint(1,1)<< p2+QPoint(-1,1)<< p4+QPoint(-1,-1)<< p3+QPoint(1,-1);
---
> polygon << (p[0] + QPoint(1,1)) << (p[1] + QPoint(-1,1)) << (p[2] + QPoint(-1,-1)) << (p[3] + QPoint(1,-1));
476,479c464,465
< p1 = QPoint(p1.x()/scaleX, p1.y()/scaleY);
< p2 = QPoint(p2.x()/scaleX, p2.y()/scaleY);
< p3 = QPoint(p3.x()/scaleX, p3.y()/scaleY);
< p4 = QPoint(p4.x()/scaleX, p4.y()/scaleY);
---
> for (int i = 0; i < 4; i++)
> p[i] = QPoint(p[i].x() / scaleX, p[i].y() / scaleY);
482,483c468,469
< mxy = meanx2(p1, p2, p3, p4);
< sxy = stdevx2(p1, p2, p3, p4);
---
> mxy = meanx2(p[0], p[1], p[2], p[3]);
> sxy = stdevx2(p[0], p[1], p[2], p[3]);
493,494c479,480
< max_w = MAX(p2.x()-p1.x(), p4.x()-p3.x());
< max_h = MAX(p3.y()-p1.y(), p4.y()-p2.y());
---
> max_w = MAX(p[1].x() - p[0].x(), p[2].x() - p[3].x());
> max_h = MAX(p[3].y() - p[0].y(), p[2].y() - p[1].y());
497c483
< mapFrom << p1<< p2<< p3<< p4;
---
> mapFrom << p[0] << p[1] << p[2] << p[3];
499c485
< mapTo << QPointF(min_w,min_h)<< QPointF(max_w,min_h)<< QPointF(min_w,max_h)<< QPointF(max_w,max_h);
---
> mapTo << QPointF(min_w, min_h) << QPointF(max_w, min_h) << QPointF(max_w, max_h) << QPointF(min_w, max_h);
510,512c496,498
< topleft = trueMtx.map(p1);
< btmright = trueMtx.map(p4);
< canvas->data->image = img.copy(QRect(topleft, btmright));
---
> pt[0] = trueMtx.map(p[0]);
> pt[2] = trueMtx.map(p[2]);
> canvas->data->image = img.copy(QRect(pt[0], pt[2]));
diff -Nard photoquick-4.3.8-orig/src/transform.h photoquick-4.3.8-temp/src/transform.h
74c74
< QPoint topleft, topright, btmleft, btmright, clk_pos, p1,p2,p3,p4;
---
> QPoint pt[4], clk_pos, p[4];
But I'm pretty sure there is a class in qt that creates a QPoint list instead of an array. What class is it and what is it with? If I can figure it out, I'll fix the PerspectiveTransform and do Dewarping based on it.
There is no specific class for list of QPoints.
But you can use QList or QVector. Like...
QList
On Tue, 18 May, 2021, 8:32 PM звездочёт, @.***> wrote:
Hi @ksharindam https://github.com/ksharindam .
Now I'm playing with the patch:
diff -Nard photoquick-4.3.8-orig/src/transform.cpp photoquick-4.3.8-temp/src/transform.cpp358,361c358,367< p1 = topleft = QPoint(0,0);< p2 = topright = QPoint(pixmap.width()-1, 0);< p3 = btmleft = QPoint(0, pixmap.height()-1);< p4 = btmright = QPoint(pixmap.width()-1, pixmap.height()-1);---> int i, sx = 1, sy = 1, st, xt, yt;> for (i = 0; i < 4; i++)> {> xt = (sx < 0) ? (pixmap.width() - 1) : 0;> yt = (sy < 0) ? (pixmap.height() - 1) : 0;> p[i] = pt[i] = QPoint(xt, yt);> st = sx;> sx = -sy; //1, -1, -1, 1> sy = st; //1, 1, -1, -1> }383,392c389,398< if (QRect(topleft, QSize(60, 60)).contains(clk_pos))< clk_area = 1; // Topleft is clicked< else if (QRect(topright, QSize(-60, 60)).contains(clk_pos))< clk_area = 2; // Topright is clicked< else if (QRect(btmleft, QSize(60, -60)).contains(clk_pos))< clk_area = 3; // Bottomleft is clicked< else if (QRect(btmright, QSize(-60, -60)).contains(clk_pos))< clk_area = 4; // bottom right corner clicked< else< clk_area = 0;---> clk_area = 0;> int i, sx = 1, sy = 1, st;> for (i = 0; i < 4; i++)> {> if (QRect(pt[i], QSize(sx 60, sy 60)).contains(clk_pos))> clk_area = i + 1;> st = sx;> sx = -sy; //1, -1, -1, 1> sy = st; //1, 1, -1, -1> }399,402c405,406< topleft = p1;< topright = p2;< btmleft = p3;< btmright = p4;---> for (int i = 0; i < 4; i++)> pt[i] = p[i];412,434c416,419< switch (clk_area) {< case 1 : { // Top left corner is clicked< new_pt = topleft + moved;< p1 = QPoint(MAX(0, new_pt.x()), MAX(0, new_pt.y()));< break;< }< case 2 : { // Top right corner is clicked< new_pt = topright + moved;< p2 = QPoint(MIN(last_pt.x(), new_pt.x()), MAX(0, new_pt.y()));< break;< }< case 3 : { // Bottom left corner is clicked< new_pt = btmleft + moved;< p3 = QPoint(MAX(0, new_pt.x()), MIN(last_pt.y(), new_pt.y()));< break;< }< case 4 : { // Bottom right corner is clicked< QPoint new_pt = btmright + moved;< p4 = QPoint(MIN(last_pt.x(), new_pt.x()), MIN(last_pt.y(), new_pt.y()));< break;< }< default:< break;---> if (clk_area > 0)> {> new_pt = pt[clk_area - 1] + moved;> p[clk_area - 1] = QPoint(MIN(last_pt.x(), MAX(0, new_pt.x())), MIN(last_pt.y(), MAX(0, new_pt.y())));445c430< polygon << p1<< p2<< p4<< p3;---> polygon << p[0] << p[1] << p[2] << p[3];448,455c433,443< calcArc(p1, p2, p3, p4, start, span);< painter.drawArc(p1.x()-30, p1.y()-30, 60,60, 16start, 16span);< calcArc(p2, p1, p4, p3, start, span);< painter.drawArc(p2.x()-30, p2.y()-30, 60,60, 16start, 16span);< calcArc(p3, p4, p1, p2, start, span);< painter.drawArc(p3.x()-30, p3.y()-30, 60,60, 16start, 16span);< calcArc(p4, p2, p3, p1, start, span);< painter.drawArc(p4.x()-30, p4.y()-30, 60,60, 16start, 16span);---> int i, j0, j1, j2, j3;> for (i = 0; i < 4; i++)> {> j0 = i;> j3 = (i + 2) % 4;> j1 = ((i - 1) < 0) ? (1 - i) : (i - 1);> j2 = (j1 + 2) % 4;> > calcArc(p[j0], p[j1], p[j2], p[j3], start, span);> painter.drawArc(p[i].x() - 30, p[i].y() - 30, 60, 60, 16 start, 16 span);> }458c446< polygon<< p1+QPoint(1,1)<< p2+QPoint(-1,1)<< p4+QPoint(-1,-1)<< p3+QPoint(1,-1);---> polygon << (p[0] + QPoint(1,1)) << (p[1] + QPoint(-1,1)) << (p[2] + QPoint(-1,-1)) << (p[3] + QPoint(1,-1));476,479c464,465< p1 = QPoint(p1.x()/scaleX, p1.y()/scaleY);< p2 = QPoint(p2.x()/scaleX, p2.y()/scaleY);< p3 = QPoint(p3.x()/scaleX, p3.y()/scaleY);< p4 = QPoint(p4.x()/scaleX, p4.y()/scaleY);---> for (int i = 0; i < 4; i++)> p[i] = QPoint(p[i].x() / scaleX, p[i].y() / scaleY);482,483c468,469< mxy = meanx2(p1, p2, p3, p4);< sxy = stdevx2(p1, p2, p3, p4);---> mxy = meanx2(p[0], p[1], p[2], p[3]);> sxy = stdevx2(p[0], p[1], p[2], p[3]);493,494c479,480< max_w = MAX(p2.x()-p1.x(), p4.x()-p3.x());< max_h = MAX(p3.y()-p1.y(), p4.y()-p2.y());---> max_w = MAX(p[1].x() - p[0].x(), p[2].x() - p[3].x());> max_h = MAX(p[3].y() - p[0].y(), p[2].y() - p[1].y());497c483< mapFrom << p1<< p2<< p3<< p4;---> mapFrom << p[0] << p[1] << p[2] << p[3];499c485< mapTo << QPointF(min_w,min_h)<< QPointF(max_w,min_h)<< QPointF(min_w,max_h)<< QPointF(max_w,max_h);---> mapTo << QPointF(min_w, min_h) << QPointF(max_w, min_h) << QPointF(max_w, max_h) << QPointF(min_w, max_h);510,512c496,498< topleft = trueMtx.map(p1);< btmright = trueMtx.map(p4);< canvas->data->image = img.copy(QRect(topleft, btmright));---> pt[0] = trueMtx.map(p[0]);> pt[2] = trueMtx.map(p[2]);> canvas->data->image = img.copy(QRect(pt[0], pt[2]));diff -Nard photoquick-4.3.8-orig/src/transform.h photoquick-4.3.8-temp/src/transform.h74c74< QPoint topleft, topright, btmleft, btmright, clk_pos, p1,p2,p3,p4;---> QPoint pt[4], clk_pos, p[4];
But I'm pretty sure there is a class in qt that creates a QPoint list instead of an array. What class is it and what is it with? As I figure it out, If I can figure it out, I'll fix the PerspectiveTransform and do Dewarping based on it.
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/ImageProcessing-ElectronicPublications/photoquick/issues/20#issuecomment-843247573, or unsubscribe https://github.com/notifications/unsubscribe-auth/AEKWXPVOHMOA2XHPJXKZOLLTOJ6PVANCNFSM4Q7UUWJQ .
@ksharindam say:
There is no specific class for list of QPoints.
QPolygon?
Yes, it is vector of QPoints
On Tue, 18 May, 2021, 10:25 PM звездочёт, @.***> wrote:
@ksharindam https://github.com/ksharindam say:
There is no specific class for list of QPoints.
QPolygon?
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/ImageProcessing-ElectronicPublications/photoquick/issues/20#issuecomment-843359091, or unsubscribe https://github.com/notifications/unsubscribe-auth/AEKWXPWM7TES7H33HPF6R5DTOKLWJANCNFSM4Q7UUWJQ .
Hi @ksharindam .
Maybe use grid: , for "Local Un-tilt"?