public void Crotate(double beta, Point c, int crop_w, int crop_h, int quality, ProgressReporter callback) { beta *= Math.PI / 180.0; float[,] oldr = r_chan; float[,] oldg = g_chan; float[,] oldb = b_chan; float[,] oldhl = hl_chan; int oldW = mWidth, oldH = mHeight; // Creating new image lock (this) { r_chan = new float[crop_w, crop_h]; g_chan = new float[crop_w, crop_h]; b_chan = new float[crop_w, crop_h]; hl_chan = new float[crop_w, crop_h]; mWidth = crop_w; mHeight = crop_h; } // Full progress int full_n = 0; object full_n_lock = new object(); // Initializing threads int threads_num = 6; Thread[] threads = new Thread[threads_num]; bool user_cancel = false; for (int q = 0; q < threads_num; q++) { threads[q] = new Thread(delegate (object obj) { try { int n1 = ((thread_data)obj).i1; int n2 = ((thread_data)obj).i2; for (int n = n1; n < n2; n++) { if (n % REPORT_EVERY_NTH_LINE == 0 && callback != null) { if (!callback((double)full_n / oldH)) throw new UserCancelException(); } for (int m = 0; m < oldW; m++) { // Rotated source matrix squares CatEye.Core.Point[] src_tr_pts = new CatEye.Core.Point[] { Point.Rotate(new CatEye.Core.Point(m, n ), -beta, c), Point.Rotate(new CatEye.Core.Point((m + 1), n ), -beta, c), Point.Rotate(new CatEye.Core.Point((m + 1), (n + 1)), -beta, c), Point.Rotate(new CatEye.Core.Point(m, (n + 1)), -beta, c) }; // Rotated and translated source matrix squares CatEye.Core.Point[] src_tr_pts2 = new CatEye.Core.Point[] { new Point(src_tr_pts[0].X - c.X + (double)crop_w / 2, src_tr_pts[0].Y - c.Y + (double)crop_h / 2), new Point(src_tr_pts[1].X - c.X + (double)crop_w / 2, src_tr_pts[1].Y - c.Y + (double)crop_h / 2), new Point(src_tr_pts[2].X - c.X + (double)crop_w / 2, src_tr_pts[2].Y - c.Y + (double)crop_h / 2), new Point(src_tr_pts[3].X - c.X + (double)crop_w / 2, src_tr_pts[3].Y - c.Y + (double)crop_h / 2), }; ConvexPolygon cp_src_tr = new ConvexPolygon(src_tr_pts2); int xmin = Math.Max((int)cp_src_tr.XMin, 0); int ymin = Math.Max((int)cp_src_tr.YMin, 0); int xmax = Math.Min((int)cp_src_tr.XMax + 1, crop_w); int ymax = Math.Min((int)cp_src_tr.YMax + 1, crop_h); for (int j = ymin; j < ymax; j++) { for (int i = xmin; i < xmax; i++) { double part = cp_src_tr.CalcProjectionToPixel(i, j, quality); // Adding colors part lock (this) { r_chan[i, j] += (float)(oldr[m, n] * part); g_chan[i, j] += (float)(oldg[m, n] * part); b_chan[i, j] += (float)(oldb[m, n] * part); hl_chan[i, j] += (float)(oldhl[m, n] * part); } } } } lock (full_n_lock) full_n ++; } } catch (UserCancelException) { user_cancel = true; } }); } // Starting threads for (int q = 0; q < threads_num; q++) { thread_data td = new thread_data(); td.i1 = (oldH / threads_num) * q; if (q < threads_num - 1) { td.i2 = (oldH / threads_num) * (q + 1); } else { td.i2 = oldH; } threads[q].Start(td); } // Waiting for threads for (int q = 0; q < threads_num; q++) { threads[q].Join(); } if (user_cancel) throw new UserCancelException(); }
private static bool SolvePoissonNeiman(float[,] I0, float[,] rho, int steps_max, float stop_dpd, SolutionReporter callback) { int w = rho.GetLength(0), h = rho.GetLength(1); float[,] I = new float[w + 2, h + 2]; float[,] Inew = new float[w + 2, h + 2]; // Setting initial values for (int i = 0; i < w + 2; i++) for (int j = 0; j < h + 2; j++) { int i1 = i; if (i == 0) i1 = 1; if (i == w + 1) i1 = w; int j1 = j; if (j == 0) j1 = 1; if (j == h + 1) j1 = h; I[i, j] = I0[i1 - 1, j1 - 1]; Inew[i, j] = I0[i1 - 1, j1 - 1]; } float delta = 0; float delta_prev = 10000; object delta_lock = new object(); for (int step = 0; step < steps_max; step ++) { // *** Horizontal iterations *** int threads_num = 6; Thread[] threads = new Thread[threads_num]; for (int q = 0; q < threads_num; q++) { threads[q] = new Thread(delegate (object obj) { int i1 = ((thread_data)obj).i1; int i2 = ((thread_data)obj).i2; float my_delta = 0; for (int i = i1; i < i2; i++) { // Run, Thomas, run! float[] alpha = new float[h + 3]; float[] beta = new float[h + 3]; alpha[1] = 0.25f; beta[1] = 0.25f * (I[i + 1, 0] + Inew[i - 1, 0]); for (int j = 1; j < h + 2; j++) { alpha[j + 1] = 1.0f / (4 - alpha[j]); float Fj; if (j < h + 1) Fj = I[i + 1, j] + Inew[i - 1, j] - 2 * rho[i - 1, j - 1]; else Fj = I[i + 1, j] + Inew[i - 1, j]; beta[j + 1] = (Fj + beta[j]) / (4f - alpha[j]); } Inew[i, h + 1] = beta[h + 2]; for (int j = h; j >= 0; j--) { double iold = I[i, j]; Inew[i, j] = alpha[j + 1] * Inew[i, j + 1] + beta[j + 1]; my_delta += (float)Math.Abs(Inew[i, j] - iold); } } lock (delta_lock) { delta += my_delta; } }); } // Starting horizontal threads for (int q = 0; q < threads_num; q++) { thread_data td = new thread_data(); td.i1 = (w / threads_num) * q + 1; if (q < threads_num - 1) { td.i2 = (w / threads_num) * (q + 1) + 1; } else { td.i2 = w + 1; } threads[q].Start(td); } // Waiting for horizontal threads for (int q = 0; q < threads_num; q++) { threads[q].Join(); } // Restoring Neiman boundary conditions after horizontal iterations for (int i = 0; i < w + 2; i++) { Inew[i, 0] = Inew[i, 1]; Inew[i, h + 1] = Inew[i, h]; } for (int j = 0; j < h + 2; j++) { Inew[0, j] = Inew[1, j]; Inew[w + 1, j] = Inew[w, j]; } // Controlling the constant after horizontal iterations float m = 0; for (int i = 0; i < w + 2; i++) for (int j = 0; j < h + 2; j++) { m += Inew[i, j]; } m /= (w+2) * (h+2); for (int i = 0; i < w + 2; i++) for (int j = 0; j < h + 2; j++) { I[i, j] = Inew[i, j] - m; } // *** Vertical iterations *** threads = new Thread[threads_num]; for (int q = 0; q < threads_num; q++) { threads[q] = new Thread(delegate (object obj) { int j1 = ((thread_data)obj).i1; int j2 = ((thread_data)obj).i2; float my_delta = 0; for (int j = j1; j < j2; j++) { // Run, Thomas, run! float[] alpha = new float[w + 3]; float[] beta = new float[w + 3]; alpha[1] = 0.25f; beta[1] = 0.25f * (I[0, j + 1] + Inew[0, j - 1]); for (int i = 1; i < w + 2; i++) { alpha[i + 1] = 1.0f / (4 - alpha[i]); float Fi; if (i < w + 1) Fi = I[i, j + 1] + Inew[i, j - 1] - 2 * rho[i - 1, j - 1]; else Fi = I[i, j + 1] + Inew[i, j - 1]; beta[i + 1] = (Fi + beta[i]) / (4f - alpha[i]); } Inew[w + 1, j] = beta[w + 2]; for (int i = w; i >= 0; i--) { double iold = I[i, j]; Inew[i, j] = alpha[i + 1] * Inew[i + 1, j] + beta[i + 1]; my_delta += (float)Math.Abs(Inew[i, j] - iold); } } lock (delta_lock) { delta += my_delta; } }); } // Starting vertical threads for (int q = 0; q < threads_num; q++) { thread_data td = new thread_data(); td.i1 = (h / threads_num) * q + 1; if (q < threads_num - 1) { td.i2 = (h / threads_num) * (q + 1) + 1; } else { td.i2 = h + 1; } threads[q].Start(td); } // Waiting for vertical threads for (int q = 0; q < threads_num; q++) { threads[q].Join(); } // Restoring Neiman boundary conditions after vertical iterations for (int i = 0; i < w + 2; i++) { Inew[i, 0] = Inew[i, 1]; Inew[i, h + 1] = Inew[i, h]; } for (int j = 0; j < h + 2; j++) { Inew[0, j] = Inew[1, j]; Inew[w + 1, j] = Inew[w, j]; } // Controlling the constant after vertical iterations m = 0; for (int i = 0; i < w + 2; i++) for (int j = 0; j < h + 2; j++) { m += Inew[i, j]; } m /= (w+2) * (h+2); for (int i = 0; i < w + 2; i++) for (int j = 0; j < h + 2; j++) { I[i, j] = Inew[i, j] - m; } for (int i = 1; i < w + 1; i++) for (int j = 1; j < h + 1; j++) { I0[i - 1, j - 1] = I[i, j]; } delta /= (float)Math.Sqrt(w * h); float dpd = Math.Abs((delta - delta_prev) / delta); // This formula is found experimentally float progress = (float)Math.Min(Math.Pow(stop_dpd / (dpd + 0.000001), 0.78), 0.999); if (callback != null) { callback(progress, I0); } if (dpd < stop_dpd) { return true; } delta_prev = delta; delta = 0; } return false; }