} //************************************ end Rect_Retain ***************************************** public void Rect_Optimal(Point[] v, bool CUT, ref CImage Result) // Calculates the corners of the rectifyed image and then makes a bilinear transformation { int MaxSize; double alphaX, alphaY, betaX, betaY, F, Height, phiX, phiY, RedX, RedY, Width, M0X, M1X, M3Y, M2Y; M0X = (double)v[1].X + (v[0].X - v[1].X) * ((double)height / 2 - v[1].Y) / ((double)v[0].Y - v[1].Y); M1X = (double)v[2].X + (v[3].X - v[2].X) * ((double)height / 2 - v[2].Y) / ((double)v[3].Y - v[2].Y); M3Y = (double)v[0].Y + (v[3].Y - v[0].Y) * ((double)width / 2 - v[0].X) / ((double)v[3].X - v[0].X); M2Y = (double)v[1].Y + (v[2].Y - v[1].Y) * ((double)width / 2 - v[1].X) / ((double)v[2].X - v[1].X); RedY = (double)(v[3].Y - v[2].Y) / (double)(v[0].Y - v[1].Y); RedX = (double)(v[3].X - v[0].X) / (double)(v[2].X - v[1].X); if (width > height) { MaxSize = width; } else { MaxSize = height; } F = 1.0 * (double)(MaxSize); alphaY = Math.Atan2(F, (double)(width / 2 - M0X)); betaY = Math.Atan2(F, (double)(M1X - width / 2)); phiY = Math.Atan2(RedY * Math.Sin(betaY) - Math.Sin(alphaY), Math.Cos(alphaY) + RedY * Math.Cos(betaY)); alphaX = Math.Atan2(F, (double)(M3Y - height / 2)); betaX = Math.Atan2(F, (double)(height / 2 - M2Y)); phiX = Math.Atan2(RedX * Math.Sin(betaX) - Math.Sin(alphaX), Math.Cos(alphaX) + RedX * Math.Cos(betaX)); double P0X = F * Math.Cos(alphaY) / Math.Sin(alphaY - phiY); double P1X = F * Math.Cos(betaY) / Math.Sin(betaY + phiY); double P0Y = F * Math.Cos(alphaX) / Math.Sin(alphaX + phiX); Width = F * (Math.Cos(alphaY) / Math.Sin(alphaY - phiY) + Math.Cos(betaY) / Math.Sin(betaY + phiY)); Height = F * (Math.Cos(alphaX) / Math.Sin(alphaX - phiX) + Math.Cos(betaX) / Math.Sin(betaX + phiX)); if (Width < 0.0 || Height < 0.0) { MessageBox.Show("The clicked area does not contain the center of the image"); return; } double OptCX = 0.0; double OptCY = 0.0; double CX = Math.Tan(phiY); double CY = Math.Tan(phiX); Optimization(F, v, CX, CY, ref OptCX, ref OptCY); CX = OptCX; CY = OptCY; CImage Out; if (CUT) { Out = new CImage((int)Width, (int)Height, N_Bits); } else { Out = new CImage(width, height, N_Bits); } Result.Copy(Out, 0); double A = 0.0, B, C, D, Det, E, G; double[] xc = new double[4]; double[] yc = new double[4]; double[] zc = new double[4]; for (int i = 0; i < 4; i++) { A = B = C = D = 0.0; A = (F / (v[i].X - width / 2) + CX); B = CY; C = width / 2 * F / (v[i].X - width / 2) + CX * width / 2 + CY * height / 2 + F; D = CX; E = (F / (v[i].Y - height / 2) + CY); G = height / 2 * F / (v[i].Y - height / 2) + CX * width / 2 + CY * height / 2 + F; Det = A * E - B * D; xc[i] = (C * E - B * G) / Det; yc[i] = (A * G - C * D) / Det; zc[i] = F - CX * (xc[i] - width / 2) - CY * (yc[i] - height / 2); // corrected } double zz; double xp, yp, xp0, xp1, yp0, yp1, xf, yf; for (int Y = 0; Y < Result.height; Y++) //=========== over the rectified image ==================== { xp0 = xc[1] + (xc[0] - xc[1]) * Y / (Result.height - 1); xp1 = xc[2] + (xc[3] - xc[2]) * Y / (Result.height - 1); for (int X = 0; X < Result.width; X++) //===================================================== { yp0 = yc[1] + (yc[2] - yc[1]) * X / (Result.width - 1); yp1 = yc[0] + (yc[3] - yc[0]) * X / (Result.width - 1); xp = xp0 + (xp1 - xp0) * X / (Result.width - 1); yp = yp0 + (yp1 - yp0) * Y / (Result.height - 1); zz = F - CX * (xp - width / 2) - CY * (yp - height / 2); // corrected xf = width / 2 + (xp - width / 2) * F / (F - CX * (xp - width / 2) - CY * (yp - height / 2)); yf = height / 2 + (yp - height / 2) * F / (F - CX * (xp - width / 2) - CY * (yp - height / 2)); if ((int)xp >= 0 && (int)xp < width && (int)yp >= 0 && (int)yp < height) { if (N_Bits == 24) { for (int ic = 0; ic < 3; ic++) { Result.Grid[ic + 3 * X + 3 * Result.width * Y] = Grid[ic + 3 * (int)xf + 3 * width * (int)yf]; } } else { Result.Grid[X + Result.width * (Result.height - 1 - Y)] = Grid[(int)xf + width * (int)yf]; } } } //================================ end for (X... ============================== } //================================== end for (Y... ================================ } //************************************ end Rect_Optimal *****************************************
} //************************************ end Rect_Central ***************************************** public void Rect_Retain(Point[] v, bool CUT, double Rel, ref CImage Result) // Calculates the corners of the rectifyed image and then makes a bilinear transformation { int MaxSize; double alphaX, alphaY, betaX, betaY, F, Height, phiX, phiY, RedX, RedY, Width, M0X, M1X, M3Y, M2Y; M0X = (double)v[1].X + (v[0].X - v[1].X) * ((double)height / 2 - v[1].Y) / ((double)v[0].Y - v[1].Y); M1X = (double)v[2].X + (v[3].X - v[2].X) * ((double)height / 2 - v[2].Y) / ((double)v[3].Y - v[2].Y); M3Y = (double)v[0].Y + (v[3].Y - v[0].Y) * ((double)width / 2 - v[0].X) / ((double)v[3].X - v[0].X); M2Y = (double)v[1].Y + (v[2].Y - v[1].Y) * ((double)width / 2 - v[1].X) / ((double)v[2].X - v[1].X); RedY = (double)(v[3].Y - v[2].Y) / (double)(v[0].Y - v[1].Y); RedX = (double)(v[3].X - v[0].X) / (double)(v[2].X - v[1].X); if (width > height) { MaxSize = width; } else { MaxSize = height; } F = 1.0 * (double)(MaxSize); alphaY = Math.Atan2(F, (double)(width / 2 - M0X)); betaY = Math.Atan2(F, (double)(M1X - width / 2)); phiY = Math.Atan2(RedY * Math.Sin(betaY) - Math.Sin(alphaY), Math.Cos(alphaY) + RedY * Math.Cos(betaY)); alphaX = Math.Atan2(F, (double)(M3Y - height / 2)); betaX = Math.Atan2(F, (double)(height / 2 - M2Y)); phiX = Math.Atan2(RedX * Math.Sin(betaX) - Math.Sin(alphaX), Math.Cos(alphaX) + RedX * Math.Cos(betaX)); double CX = Math.Tan(phiY); // X-coefficient of plane P double CY = Math.Tan(phiX); // Y-coefficient of plane double OptCX = 0.0, OptCY = 0.0; Optimization(F, v, CX, CY, ref OptCX, ref OptCY); CX = OptCX; CY = OptCY; double A = 0.0, B, C, D, Det, E, G; double[] xc = new double[8]; double[] yc = new double[8]; double[] zc = new double[8]; Point[] w = new Point[8]; for (int i = 0; i < 4; i++) { w[i] = v[i]; } for (int i = 0; i < 4; i++) { A = (F / (w[i].X - width / 2) + CX); B = CY; C = width / 2 * F / (w[i].X - width / 2) + CX * width / 2 + CY * height / 2 + F; D = CX; E = (F / (w[i].Y - height / 2) + CY); G = height / 2 * F / (w[i].Y - height / 2) + CX * width / 2 + CY * height / 2 + F; Det = A * E - B * D; xc[i] = (C * E - B * G) / Det; yc[i] = (A * G - C * D) / Det; zc[i] = F - CX * (xc[i] - width / 2) - CY * (yc[i] - height / 2); // corrected } // Transforming the points: for (int i = 0; i < 4; i++) // new points: { xc[i + 4] = (int)(width / 2 + Rel * (xc[i] - width / 2)); yc[i + 4] = (int)(height / 2 + Rel * (yc[i] - height / 2)); zc[i + 4] = (int)(F + Rel * (zc[i] - F)); } Width = Math.Sqrt(Math.Pow((xc[7] - xc[4]), 2.0) + Math.Pow((yc[7] - yc[4]), 2.0) + Math.Pow((zc[7] - zc[4]), 2.0)); Height = Math.Sqrt(Math.Pow((xc[4] - xc[5]), 2.0) + Math.Pow((yc[4] - yc[5]), 2.0) + Math.Pow((zc[4] - zc[5]), 2.0)); CImage Out; Out = new CImage((int)Width, (int)Height, N_Bits); Result.Copy(Out, 0); double zz; double xp, yp, xp0, xp1, yp0, yp1, xf, yf; for (int Y = 0; Y < Result.height; Y++) //=========== over the rectified image ==================== { xp0 = xc[5] + (xc[4] - xc[5]) * Y / (Result.height - 1); xp1 = xc[6] + (xc[7] - xc[6]) * Y / (Result.height - 1); for (int X = 0; X < Result.width; X++) //===================================================== { yp0 = yc[5] + (yc[6] - yc[5]) * X / (Result.width - 1); yp1 = yc[4] + (yc[7] - yc[4]) * X / (Result.width - 1); xp = xp0 + (xp1 - xp0) * X / (Result.width - 1); // +100.0; yp = yp0 + (yp1 - yp0) * Y / (Result.height - 1); zz = F - CX * (xp - width / 2) - CY * (yp - height / 2); // correted xf = width / 2 + (xp - width / 2) * F / (F - CX * (xp - width / 2) - CY * (yp - height / 2)); yf = height / 2 + (yp - height / 2) * F / (F - CX * (xp - width / 2) - CY * (yp - height / 2)); if ((int)xf >= 0 && (int)xf < width && (int)yf >= 0 && (int)yf < height) { if (N_Bits == 24) { for (int ic = 0; ic < 3; ic++) { Result.Grid[ic + 3 * X + 3 * Result.width * Y] = Grid[ic + 3 * (int)xf + 3 * width * (int)yf]; } } else { Result.Grid[X + Result.width * (Result.height - 1 - Y)] = Grid[(int)xf + width * (int)yf]; } } } //================================ end for (X... ============================== } //================================== end for (Y... ================================ } //************************************ end Rect_Retain *****************************************