package ip.gui.frames;
import ip.gui.dialog.RotoLog;
import ip.gui.DotArray;
import math.Mat3;
import math.Mat4;
import ip.gui.TransformTable;
import java.awt.*;
import java.awt.event.ActionEvent;
public class XformFrame extends ColorFrame {
private AffineFrame af = null;
private Menu xformMenu = getMenu("Xform");
private MenuItem showAffineFrame_mi =
addMenuItem(xformMenu, "[T-A]Show affine frame..");
private MenuItem showDotArrayFrame_mi =
addMenuItem(xformMenu, "[T-D]ot array..");
private Menu turnMenu = getMenu("Turn");
private MenuItem turn90_mi =
addMenuItem(turnMenu, "[E-9]0 turn and back");
private MenuItem turn180_mi =
addMenuItem(turnMenu, "[T-1] turn 90 increments");
private MenuItem mirror_mi =
addMenuItem(turnMenu, "[T-m] mirror");
private MenuItem rotate_mi =
addMenuItem(turnMenu, "rotate...");
private MenuItem scale_mi =
addMenuItem(turnMenu, "scale by 1/2");
public void copyToChildFrame() {
short _r[][] = new short[getImageWidth()][getImageHeight()];
short _g[][] = new short[getImageWidth()][getImageHeight()];
short _b[][] = new short[getImageWidth()][getImageHeight()];
for (int x = 0; x < getImageWidth(); x++)
for (int y = 0; y < getImageHeight(); y++) {
_r[x][y] = getR()[x][y];
_g[x][y] = getG()[x][y];
_b[x][y] = getB()[x][y];
}
setChild(new TopFrame(
"Child",
_r, _g, _b));
}
public void actionPerformed(ActionEvent e) {
if (match(e, scale_mi)) {
scale(2);
}
if (match(e, showDotArrayFrame_mi)) {
showDotArrayFrame();
return;
}
if (match(e, mirror_mi)) {
mirror();
return;
}
if (match(e, showAffineFrame_mi)) {
showAffineFrame();
return;
}
if (match(e, turn180_mi)) {
turn180();
return;
}
if (match(e, turn90_mi)) {
turn90();
return;
}
if (match(e, rotate_mi)) {
rotate();
return;
}
super.actionPerformed(e);
}
public void showDotArrayFrame() {
DotArray af = new DotArray(
"DotArray", new TopFrame("TopFrame"));
af.setVisible(true);
}
public void setPose(double theta, double sx, double sy) {
Mat3 tr1 = new Mat3();
Mat3 tr2 = new Mat3();
Mat3 rt = new Mat3();
Mat3 sc = new Mat3();
Mat3 at;
int xc = getImageWidth() / 2;
int yc = getImageHeight() / 2;
tr1.setTranslation(xc, yc);
sc.setScale(sx, sy);
rt.setRotation(theta);
tr2.setTranslation(-xc, -yc);
at = tr1.multiply(rt);
at = at.multiply(sc);
at = at.multiply(tr2);
xform(at);
}
public void setPoseFeedback(double theta, double sx, double sy) {
Mat3 tr1 = new Mat3();
Mat3 tr2 = new Mat3();
Mat3 rt = new Mat3();
Mat3 sc = new Mat3();
Mat3 at;
int xc = getImageWidth() / 2;
int yc = getImageHeight() / 2;
tr1.setTranslation(xc, yc);
sc.setScale(sx, sy);
rt.setRotation(theta);
tr2.setTranslation(-xc, -yc);
at = tr1.multiply(rt);
at = at.multiply(sc);
at = at.multiply(tr2);
xformFeedback(at);
}
public void turn(double angle) {
setPose(angle, 1, 1);
}
public void turnFeedback(double angle) {
setPoseFeedback(angle, 1, 1);
}
public void mirror() {
turn90();
turn180();
}
public void turn90() {
short ro[][] = new short[getR()[0].length][getR().length];
short go[][] = new short[getR()[0].length][getR().length];
short bo[][] = new short[getR()[0].length][getR().length];
for (int x = 0; x < getR().length; x++)
for (int y = 0; y < getR()[0].length; y++) {
ro[y][x] = getR()[x][y];
go[y][x] = getG()[x][y];
bo[y][x] = getB()[x][y];
}
setR(ro);
setG(go);
setB(bo);
setImageHeight(getR().length);
setImageWidth(getR()[0].length);
short2Image();
}
public void turn180() {
short ro[][] = new short[getR()[0].length][getR().length];
short go[][] = new short[getR()[0].length][getR().length];
short bo[][] = new short[getR()[0].length][getR().length];
for (int y = 0,k = getR()[0].length - 1; y < getR()[0].length; y++, k--)
for (int x = 0; x < getR().length; x++) {
ro[k][x] = getR()[x][y];
go[k][x] = getG()[x][y];
bo[k][x] = getB()[x][y];
}
setR(ro);
setG(go);
setB(bo);
setImageHeight(getR().length);
setImageWidth(getR()[0].length);
short2Image();
}
public void showAffineFrame() {
Rectangle r = getBounds();
Dimension d = r.getSize();
af = new AffineFrame("Affine Frame", this, getImageWidth(), getImageHeight());
af.setLocation(d.width, d.height);
af.setSize(150, 150);
af.setVisible(true);
}
public Point invertMap(double a[][], double u, double v) {
double t1 = u * v;
double c[] = new double[2];
c[0] = t1 * a[0][0] + u * a[1][0] + v * a[2][0] + a[3][0];
c[1] = t1 * a[0][1] + u * a[1][1] + v * a[2][1] + a[3][1];
return interpolateCoordinates(c);
}
public Point interpolateCoordinates(double c[]) {
return new Point((int) c[0], (int) c[1]);
}
public void applyAffineFrame2() {
}
public Mat3 infer3PointA(Polygon sp, Polygon dp) {
double s3 [][] = {
{sp.xpoints[0], sp.xpoints[1], sp.xpoints[2]},
{sp.ypoints[0], sp.ypoints[1], sp.ypoints[2]},
{1, 1, 1}};
double d3 [][] = {
{dp.xpoints[0], dp.xpoints[1], dp.xpoints[2]},
{dp.ypoints[0], dp.ypoints[1], dp.ypoints[2]},
{1, 1, 1}};
Mat3 d3Mat = new Mat3(d3);
Mat3 s3Mat = new Mat3(s3);
Mat3 s3MatInverse = s3Mat.invert();
Mat3 a = d3Mat.multiply(s3MatInverse);
return a;
}
public double[][] infer4PointA(Polygon sp, Polygon dp) {
int xd[] = dp.xpoints;
int yd[] = dp.ypoints;
int xs[] = sp.xpoints;
int ys[] = sp.ypoints;
double d4 [][] = {
{xd[0], xd[1], xd[2], xd[3]},
{yd[0], yd[1], yd[2], yd[3]},
};
double s4[][] = {
{xs[0], xs[1], xs[2], xs[3]},
{ys[0], ys[1], ys[2], ys[3]},
{xs[0] * ys[0], xs[1] * ys[1], xs[2] * ys[2], xs[3] * ys[3]},
{1, 1, 1, 1},
};
Mat4 s4Mat = new Mat4(s4);
Mat4 s4MatInverse = s4Mat.invert();
double[][] a = s4MatInverse.multiply2x4(d4);
return a;
}
public double quadraticRoot(double a, double b, double c) {
if (a == 0) a = 0.00001;
double sqrtArg = b * b - 4 * a * c;
double aa = 2 * a;
if (sqrtArg < 0) return -b / aa; double root1 = (-b + Math.sqrt(sqrtArg)) / aa;
double root2 = (-b - Math.sqrt(sqrtArg)) / aa;
if ((root1 >= 0) && (root1 < getImageHeight())) return root1;
if ((root2 >= 0) && (root2 < getImageHeight())) return root2;
if (root1 > getImageHeight()) return getImageHeight();
return 0;
}
public double[] inverseMap4(double a[][], double xp, double yp) {
double as =
-a[1][1] * a[0][2]
+ a[1][2] * a[0][1];
double b =
a[0][2] * yp + a[1][0] * a[0][1] - a[0][0] * a[1][1]
- a[1][2] * xp + a[1][2] * a[0][3] - a[0][2] * a[1][3];
double c = yp * a[0][0]
- a[1][0] * xp
+ a[1][0] * a[0][3]
- a[1][3] * a[0][0];
double y = quadraticRoot(as, b, c);
double x =
(xp - a[0][1] * y - a[0][3]) / (a[0][0] + a[0][2] * y);
double p[] = {x, y};
return p;
}
public void applyBilinear4Points(
Polygon sourcePoly, Polygon destPoly) {
double a[][];
try {
a = infer4PointA(
sourcePoly,
destPoly);
inverseBilinearXform(a);
} catch (ArithmeticException e) {
System.out.println("error in user input, trying 3 point transform");
xform(
infer3PointA(sourcePoly, destPoly));
}
}
public void applyBilinear4PointsFeedback(
Polygon sourcePoly, Polygon destPoly) {
double a[][];
a = infer4PointA(
sourcePoly,
destPoly);
inverseBilinearXformfeedback(a);
}
public void applyBilinear4Points() {
Polygon sourcePoly = new Polygon();
sourcePoly.addPoint(0, 0);
sourcePoly.addPoint(getImageWidth(), 0);
sourcePoly.addPoint(getImageWidth(), getImageHeight());
sourcePoly.addPoint(0, getImageHeight());
Polygon destPoly = af.getPolygon();
applyBilinear4Points(sourcePoly, destPoly);
}
public void applyBilinear4PointsFeedback() {
Polygon sourcePoly = new Polygon();
sourcePoly.addPoint(0, 0);
sourcePoly.addPoint(getImageWidth(), 0);
sourcePoly.addPoint(getImageWidth(), getImageHeight());
sourcePoly.addPoint(0, getImageHeight());
Polygon destPoly = af.getPolygon();
applyBilinear4PointsFeedback(sourcePoly, destPoly);
}
public void inverseBilinearXform(double a[][]) {
int w = getImageWidth();
int h = getImageHeight();
short rn[][] = new short[w][h];
short gn[][] = new short[w][h];
short bn[][] = new short[w][h];
double p[] = new double[2];
int xp, yp;
for (int x = 0; x < w; x++)
for (int y = 0; y < h; y++) {
p = inverseMap4(a, x, y);
xp = (int) (p[0]);
yp = (int) (p[1]);
if ((xp < w - 1) && (yp < h - 1) && (xp > 0) && (yp > 0)) {
rn[x][y] = getR()[xp][yp];
gn[x][y] = getG()[xp][yp];
bn[x][y] = getB()[xp][yp];
}
}
setR(rn);
setG(gn);
setB(bn);
short2Image();
}
public void colorize() {
TransformTable tt = new TransformTable(256);
tt.randomize();
short lut[] = tt.getLut();
for (int y = 0; y < getImageHeight(); y++)
for (int x = 0; x < getImageWidth(); x++) {
getR()[x][y] = lut[getR()[x][y]];
getG()[x][y] = getR()[x][y];
getB()[x][y] = getR()[x][y];
}
short2Image();
}
public void zedSquare() {
int w = getImageWidth();
int h = getImageHeight();
int xc = w / 2;
int yc = h / 2;
short rn[][] = new short[getImageWidth()][getImageHeight()];
short gn[][] = new short[getImageWidth()][getImageHeight()];
short bn[][] = new short[getImageWidth()][getImageHeight()];
double p[] = new double[2];
int xp, yp;
double R = Math.sqrt(w * w / 4 + h * h / 4);
for (int x = 0; x < w; x++)
for (int y = 0; y < h; y++) {
double dx = x - xc;
double dy = y - yc;
double radius = Math.sqrt(dx * dx + dy * dy);
double a = (180 / Math.PI) * Math.atan2(dy, dx);
a = a * 2;
radius = radius * radius / R;
a = a * Math.PI / 180;
p[0] = radius * Math.cos(a);
p[1] = radius * Math.sin(a);
xp = (int) p[0] + xc;
yp = (int) p[1] + yc;
if ((xp < w) && (yp < h) && (xp >= 0) && (yp >= 0)) {
rn[x][y] = getR()[xp][yp];
gn[x][y] = getG()[xp][yp];
bn[x][y] = getB()[xp][yp];
}
}
setR(rn);
setG(gn);
setB(bn);
short2Image();
}
public void zedSquare(float dilate) {
int w = getImageWidth();
int h = getImageHeight();
int xc = w / 2;
int yc = h / 2;
short rn[][] = new short[getImageWidth()][getImageHeight()];
short gn[][] = new short[getImageWidth()][getImageHeight()];
short bn[][] = new short[getImageWidth()][getImageHeight()];
double p[] = new double[2];
int xp, yp;
double R = Math.sqrt(w * w / 4 + h * h / 4);
for (int x = 0; x < w; x++)
for (int y = 0; y < h; y++) {
double dx = x - xc;
double dy = y - yc;
double radius = Math.sqrt(dx * dx + dy * dy);
double a = (180 / Math.PI) * Math.atan2(dy, dx);
a = a * 2;
radius = radius * radius / R;
a = a * Math.PI / 180;
radius = dilate * radius;
p[0] = radius * Math.cos(a);
p[1] = radius * Math.sin(a);
xp = (int) p[0] + xc;
yp = (int) p[1] + yc;
if ((xp < w) && (yp < h) && (xp >= 0) && (yp >= 0)) {
rn[x][y] = getR()[xp][yp];
gn[x][y] = getG()[xp][yp];
bn[x][y] = getB()[xp][yp];
}
}
setR(rn);
setG(gn);
setB(bn);
short2Image();
}
public void inverseBilinearXformfeedback(double a[][]) {
int w = getImageWidth();
int h = getImageHeight();
double p[] = new double[2];
int xp, yp;
double startPoint[] = inverseMap4(a, 0, 0);
double endPoint[] = inverseMap4(a, w - 1, h - 1);
int x1 = (int) startPoint[0];
int y1 = (int) startPoint[1];
int x2 = (int) endPoint[0];
int y2 = (int) endPoint[1];
for (int x = x1; x < x2; x++)
for (int y = y1; y < y2; y++) {
p = inverseMap4(a, x, y);
xp = (int) (p[0]);
yp = (int) (p[1]);
if ((xp < w - 1) && (yp < h - 1) && (xp > 0) && (yp > 0)) {
getR()[x][y] = getR()[xp][yp];
getG()[x][y] = getG()[xp][yp];
getB()[x][y] = getB()[xp][yp];
}
}
short2Image();
}
public void applyAffineFrameThreePoints() {
Polygon sourcePoly = new Polygon();
sourcePoly.addPoint(0, 0);
sourcePoly.addPoint(getImageWidth(), 0);
sourcePoly.addPoint(getImageWidth(), getImageHeight());
xform(
infer3PointA(sourcePoly,
af.getPolygon()));
}
public void rotate() {
String prompts[] = {
"angle (degs):"
};
String defaults[] = {"0.0"};
String title = "Rotation Dialog";
new RotoLog(
this,
title,
prompts,
defaults, 9);
}
public void scale(int scale) {
int nw = getImageWidth() * scale;
int nh = getImageHeight() * scale;
short sr[][] = new short[nw][nh];
short sg[][] = new short[nw][nh];
short sb[][] = new short[nw][nh];
for (int y = 0; y < getImageHeight(); y++)
for (int j = 0; j < nw; j++)
for (int x = 0; x < getImageWidth(); x++)
for (int i = 0; i < nh; i++) {
sr[i][j] = getR()[x][y];
sg[i][j] = getG()[x][y];
sb[i][j] = getB()[x][y];
}
setR(sr);
setG(sg);
setB(sb);
short2Image();
}
public XformFrame(String title) {
super(title);
MenuBar menuBar = getMenuBar();
xformMenu.add(turnMenu);
menuBar.add(xformMenu);
setMenuBar(menuBar);
}
public static void main(String args[]) {
String title = "Kahindu by D. Lyon";
if (args.length == 1)
title = args[0];
XformFrame xf =
new XformFrame(title);
xf.setVisible(true);
}
public void fishEye() {
fishEye(getImageWidth() / 2, getImageHeight() / 2, 2.1);
}
public void fishEye(double gamma) {
fishEye(getImageWidth() / 2, getImageHeight() / 2, gamma);
}
public void fishEye(int xc, int yc, double gamma) {
int w = getImageWidth();
int h = getImageHeight();
short rn[][] = new short[getImageWidth()][getImageHeight()];
short gn[][] = new short[getImageWidth()][getImageHeight()];
short bn[][] = new short[getImageWidth()][getImageHeight()];
double p[] = new double[2];
int xp, yp;
double R = Math.sqrt(w * w / 4 + h * h / 4);
for (int x = 0; x < w; x++)
for (int y = 0; y < h; y++) {
double dx = x - xc;
double dy = y - yc;
double radius = Math.sqrt(dx * dx + dy * dy);
double u = Math.pow(radius, gamma) / R;
double a = Math.atan2(dy, dx);
p[0] = u * Math.cos(a);
p[1] = u * Math.sin(a);
xp = (int) p[0] + xc;
yp = (int) p[1] + yc;
if ((xp < w) && (yp < h) && (xp >= 0) && (yp >= 0)) {
rn[x][y] = getR()[xp][yp];
gn[x][y] = getG()[xp][yp];
bn[x][y] = getB()[xp][yp];
}
}
setR(rn);
setG(gn);
setB(bn);
short2Image();
}
public void polarTransform() {
int w = getImageWidth();
int h = getImageHeight();
int xc = w / 2;
int yc = h / 2;
short rn[][] = new short[getImageWidth()][getImageHeight()];
short gn[][] = new short[getImageWidth()][getImageHeight()];
short bn[][] = new short[getImageWidth()][getImageHeight()];
double p[] = new double[2];
int xp, yp;
for (int x = 0; x < w; x++)
for (int y = 0; y < h; y++) {
double dx = x - xc;
double dy = y - yc;
double radius = Math.sqrt(dx * dx + dy * dy);
double a = (180 / Math.PI) * Math.atan2(dy, dx);
a = a + radius;
a = a * Math.PI / 180;
p[0] = radius * Math.cos(a);
p[1] = radius * Math.sin(a);
xp = (int) p[0] + xc;
yp = (int) p[1] + yc;
if ((xp < w) && (yp < h) && (xp >= 0) && (yp >= 0)) {
rn[x][y] = getR()[xp][yp];
gn[x][y] = getG()[xp][yp];
bn[x][y] = getB()[xp][yp];
}
}
setR(rn);
setG(gn);
setB(bn);
short2Image();
}
public void polarTransform(double t, double ta) {
int w = getImageWidth();
int h = getImageHeight();
int xc = w / 2;
int yc = h / 2;
short rn[][] = new short[getImageWidth()][getImageHeight()];
short gn[][] = new short[getImageWidth()][getImageHeight()];
short bn[][] = new short[getImageWidth()][getImageHeight()];
double p[] = new double[2];
int xp, yp;
for (int x = 0; x < w; x++)
for (int y = 0; y < h; y++) {
double dx = x - xc;
double dy = y - yc;
double radius = (t * 2) * Math.sqrt(dx * dx + dy * dy);
double a = (180 / Math.PI) * Math.atan2(dy, dx);
a = a + radius;
a = ta * a * Math.PI / 180;
p[0] = radius * Math.cos(a);
p[1] = radius * Math.sin(a);
xp = (int) p[0] + xc;
yp = (int) p[1] + yc;
if ((xp < w) && (yp < h) && (xp >= 0) && (yp >= 0)) {
rn[x][y] = getR()[xp][yp];
gn[x][y] = getG()[xp][yp];
bn[x][y] = getB()[xp][yp];
}
}
setR(rn);
setG(gn);
setB(bn);
short2Image();
}
public void sqrt() {
sqrt(1.0);
}
public void sqrt(double t) {
int w = getImageWidth();
int h = getImageHeight();
int xc = w / 2;
int yc = h / 2;
short rn[][] = new short[getImageWidth()][getImageHeight()];
short gn[][] = new short[getImageWidth()][getImageHeight()];
short bn[][] = new short[getImageWidth()][getImageHeight()];
double p[] = new double[2];
int xp, yp;
double R = Math.sqrt(w * w / 4 + h * h / 4);
for (int x = 0; x < w; x++)
for (int y = 0; y < h; y++) {
double dx = x - xc;
double dy = y - yc;
double radius = t * Math.sqrt(dx * dx + dy * dy);
double a = (180 / Math.PI) * Math.atan2(dy, dx);
radius = Math.sqrt(radius * R);
a = t * a * Math.PI / 180;
p[0] = radius * Math.cos(a);
p[1] = radius * Math.sin(a);
xp = (int) p[0] + xc;
yp = (int) p[1] + yc;
if ((xp < w) && (yp < h) && (xp >= 0) && (yp >= 0)) {
rn[x][y] = getR()[xp][yp];
gn[x][y] = getG()[xp][yp];
bn[x][y] = getB()[xp][yp];
}
}
setR(rn);
setG(gn);
setB(bn);
short2Image();
}
public void xform(Mat3 transform) {
int w = getImageWidth();
int h = getImageHeight();
short rn[][] = new short[getImageWidth()][getImageHeight()];
short gn[][] = new short[getImageWidth()][getImageHeight()];
short bn[][] = new short[getImageWidth()][getImageHeight()];
int p[] = new int[3];
int xp, yp;
transform = transform.invert();
for (int x = 0; x < w; x++)
for (int y = 0; y < h; y++) {
p = transform.multiply(x, y, 1);
xp = (p[0] / p[2]);
yp = (p[1] / p[2]);
if ((xp < w) && (yp < h) && (xp >= 0) && (yp >= 0)) {
rn[x][y] = getR()[xp][yp];
gn[x][y] = getG()[xp][yp];
bn[x][y] = getB()[xp][yp];
}
}
setR(rn);
setG(gn);
setB(bn);
short2Image();
}
public void xformFeedback(Mat3 transform) {
int w = getImageWidth();
int h = getImageHeight();
int p[] = new int[3];
int xp, yp;
transform = transform.invert();
int startPoint[] = transform.multiply(0, 0, 1);
int endPoint[] = transform.multiply(w - 1, h - 1, 1);
for (int x = startPoint[0]; x < endPoint[0]; x++)
for (int y = startPoint[1]; y < endPoint[1]; y++) {
p = transform.multiply(x, y, 1);
xp = p[0];
yp = p[1];
if (x < 0 || x >= getR().length) continue;
if (y < 0 || y >= getR()[0].length) continue;
try {
if ((xp < w) && (yp < h) && (xp >= 0) && (yp >= 0)) {
getR()[x][y] = getR()[xp][yp];
getG()[x][y] = getG()[xp][yp];
getB()[x][y] = getB()[xp][yp];
}
} catch (Exception e) {
System.out.println(e +
"x,y=" + x + "," + y + " xp,yp=" + xp + "," + "yp");
break;
}
}
short2Image();
}
public AffineFrame getAf() {
return af;
}
public void setAf(AffineFrame af) {
this.af = af;
}
public Menu getXformMenu() {
return xformMenu;
}
public void setXformMenu(Menu xformMenu) {
this.xformMenu = xformMenu;
}
public MenuItem getShowAffineFrame_mi() {
return showAffineFrame_mi;
}
public void setShowAffineFrame_mi(MenuItem showAffineFrame_mi) {
this.showAffineFrame_mi = showAffineFrame_mi;
}
public MenuItem getShowDotArrayFrame_mi() {
return showDotArrayFrame_mi;
}
public void setShowDotArrayFrame_mi(MenuItem showDotArrayFrame_mi) {
this.showDotArrayFrame_mi = showDotArrayFrame_mi;
}
public Menu getTurnMenu() {
return turnMenu;
}
public void setTurnMenu(Menu turnMenu) {
this.turnMenu = turnMenu;
}
public MenuItem getTurn90_mi() {
return turn90_mi;
}
public void setTurn90_mi(MenuItem turn90_mi) {
this.turn90_mi = turn90_mi;
}
public MenuItem getTurn180_mi() {
return turn180_mi;
}
public void setTurn180_mi(MenuItem turn180_mi) {
this.turn180_mi = turn180_mi;
}
public MenuItem getMirror_mi() {
return mirror_mi;
}
public void setMirror_mi(MenuItem mirror_mi) {
this.mirror_mi = mirror_mi;
}
public MenuItem getRotate_mi() {
return rotate_mi;
}
public void setRotate_mi(MenuItem rotate_mi) {
this.rotate_mi = rotate_mi;
}
public MenuItem getScale_mi() {
return scale_mi;
}
public void setScale_mi(MenuItem scale_mi) {
this.scale_mi = scale_mi;
}
}