override protected void Render(Image image, Drawable drawable) { var progress = new Progress(_("Colorizing...")); var rectangle = drawable.MaskIntersect; // Fix me: replace with x1, y1, x2, y2 int i = rectangle.X1; int j = rectangle.Y1; int ii = rectangle.X2; int jj = rectangle.Y2; bool hasSel = (rectangle != null); if (!hasSel || _useEntireImage) { j = i = 0; jj = image.Width; ii = image.Height; } Drawable sel = null; int threshGuc = (int)(_thresh * 255); PixelRgn selRgn = null; if (hasSel) { sel = image.Selection; selRgn = new PixelRgn(sel, rectangle, false, false); } var srcRgn = new PixelRgn(drawable, rectangle, false, false); var dstRgn = new PixelRgn(drawable, rectangle, true, true); var markRgn = new PixelRgn(_marked, rectangle, false, false); int h = srcRgn.H; int w = srcRgn.W; var A = new double[WindowPixels, h *w]; var AI = new int[WindowPixels * h * w]; var AJ = new int[WindowPixels * h * w]; var Y = new double[h, w]; var I = new double[h, w]; var Q = new double[h, w]; double[,] inI = null; double[,] inQ = null; if (_useChroma) { inI = new double[h, w]; inQ = new double[h, w]; } bool[,] mask = new bool[h, w]; Tile.CacheDefault(drawable); if (sel != null) { // Retarded check for selections, because gimp doesn't // _REALLY_ return FALSE when there's no selection. if (j == 0 && i == 0 && jj == drawable.Width && ii == drawable.Height) { bool goodSelection = false; foreach (var pixel in new ReadPixelIterator(sel, RunMode.Noninteractive)) { if (pixel[0] != 0) { goodSelection = true; break; } } if (!goodSelection) { sel.Detach(); sel = null; } } } Pixel[] selRow = null; var whitePixel = new Pixel(255, 255, 255); for (i = 0; i < h; i++) { var imgRow = srcRgn.GetRow(srcRgn.X, srcRgn.Y + i, w); var markRow = markRgn.GetRow(markRgn.X, markRgn.Y + i, w); if (sel != null) { selRow = selRgn.GetRow(selRgn.X, selRgn.Y + i, w); } for (j = 0; j < w; j++) { var imgPixel = imgRow[j]; var markPixel = markRow[j]; int selIdx = (sel != null) ? j : 0; double iY, iI, iQ; double mY; rgb2yiq(imgPixel, out iY, out iI, out iQ); if (_useChroma) { inI[i, j] = iI; inQ[i, j] = iQ; } if (_includeOriginal) { var diff = imgPixel - markPixel;; int delta = Math.Abs(diff.Red) + Math.Abs(diff.Green) + Math.Abs(diff.Blue); } // big dirty if statement if (_pureWhite && markPixel.IsSameColor(whitePixel)) { mask[i, j] = true; } else if ((_includeOriginal && !imgPixel.IsSameColor(markPixel)) || (!_includeOriginal && markPixel.Alpha >= threshGuc)) { mask[i, j] = true; rgb2yiq(markPixel, out mY, out iI, out iQ); } else if (sel != null && selRow[selIdx].Red < threshGuc) { mask[i, j] = true; } else { mask[i, j] = false; iI = iQ = 0; } Y[i, j] = iY; I[i, j] = iI; Q[i, j] = iQ; } } if (sel != null) { sel.Detach(); } progress.Update(0.1); int n = 0; for (i = 0; i < h; i++) { for (j = 0; j < w; j++) { if (!mask[i, j]) { int min_ii = Math.Max(0, i - WindowRadius); int max_ii = Math.Min(h - 1, i + WindowRadius); int min_jj = Math.Max(0, j - WindowRadius); int max_jj = Math.Min(w - 1, j + WindowRadius); var vary = new int[WindowPixels]; var varx = new int[WindowPixels]; var var = new double[WindowPixels]; int count = 0; double sum_sq = 0; double sum = 0; double min_variance = 1.0; for (ii = min_ii; ii <= max_ii; ii++) { for (jj = min_jj; jj <= max_jj; jj++) { double val = Y[ii, jj]; sum += val; sum_sq += val * val; if (ii == i && jj == j) { continue; } vary[count] = i * w + j; varx[count] = ii * w + jj; var[count] = val - Y[i, j]; var[count] *= var[count]; if (_useChroma) { val = inI[ii, jj] - inI[i, j]; var[count] += val * val; val = inQ[ii, jj] - inQ[i, j]; var[count] += val * val; } if (var[count] < min_variance) { min_variance = var[count]; } ++count; } } double sigma = (sum_sq - (sum * sum) / (double)(count + 1)) / (double)count; if (sigma < 0.000002) { sigma = 0.000002; } else if (sigma < (min_variance / LN_100)) { sigma = min_variance / LN_100; } sum = 0; for (ii = 0; ii < count; ii++) { var[ii] = Math.Exp(-var[ii] / sigma); sum += var[ii]; } for (ii = 0; ii < count; ii++) { AI[n] = vary[ii]; AJ[n] = varx[ii]; // Fix me: just A[i, j]? A[n / (h * w), n % (h * w)] = -var[ii] / sum; ++n; } } AI[n] = AJ[n] = i * w + j; // Fix me: just A[i, j]? A[n / (h * w), n % (h * w)] = 1.0; ++n; } } UmfPack umf = new UmfPack(); umf.Defaults(); var Ax = new double[WindowPixels, h *w]; var Ap = new int[h * w + 1]; var Ai = new int[WindowPixels * h * w]; var Map = new int[WindowPixels * h * w]; umf.TripletToCol(h * w, h * w, n, AI, AJ, A, Ap, Ai, Ax, Map); umf.Symbolic(h * w, h * w, Ap, Ai, Ax); umf.Numeric(Ap, Ai, Ax); umf.FreeSymbolic(); progress.Update(0.3); var outI = new double[h, w]; var outQ = new double[h, w]; umf.Solve(Ap, Ai, Ax, outI, I); progress.Update(0.6); umf.Solve(Ap, Ai, Ax, outQ, Q); umf.FreeNumeric(); progress.Update(0.9); for (i = 0; i < h; i++) { // FIXME: This is only for the alpha channel.. var imgRow = srcRgn.GetRow(srcRgn.X, srcRgn.Y + i, w); for (j = 0; j < w; j++) { yiq2rgb(Y[i, j], outI[i, j], outQ[i, j], imgRow[j]); } dstRgn.SetRow(imgRow, dstRgn.X, dstRgn.Y + i); } drawable.Flush(); drawable.MergeShadow(true); drawable.Update(dstRgn.X, dstRgn.Y, dstRgn.W, dstRgn.H); progress.Update(1.0); }
protected override void Render(Image image, Drawable drawable) { var progress = new Progress(_("Colorizing...")); var rectangle = drawable.MaskIntersect; // Fix me: replace with x1, y1, x2, y2 int i = rectangle.X1; int j = rectangle.Y1; int ii = rectangle.X2; int jj = rectangle.Y2; bool hasSel = (rectangle != null); if (!hasSel || _useEntireImage) { j = i = 0; jj = image.Width; ii = image.Height; } Drawable sel = null; int threshGuc = (int) (_thresh * 255); PixelRgn selRgn = null; if (hasSel) { sel = image.Selection; selRgn = new PixelRgn(sel, rectangle, false, false); } var srcRgn = new PixelRgn(drawable, rectangle, false, false); var dstRgn = new PixelRgn(drawable, rectangle, true, true); var markRgn = new PixelRgn(_marked, rectangle, false, false); int h = srcRgn.H; int w = srcRgn.W; var A = new double[WindowPixels, h * w]; var AI = new int[WindowPixels * h * w]; var AJ = new int[WindowPixels * h * w]; var Y = new double[h, w]; var I = new double[h, w]; var Q = new double[h, w]; double[,] inI = null; double[,] inQ = null; if (_useChroma) { inI = new double[h, w]; inQ = new double[h, w]; } bool[,] mask = new bool[h, w]; Tile.CacheDefault(drawable); if (sel != null) { // Retarded check for selections, because gimp doesn't // _REALLY_ return FALSE when there's no selection. if (j == 0 && i == 0 && jj == drawable.Width && ii == drawable.Height) { bool goodSelection = false; foreach (var pixel in new ReadPixelIterator(sel, RunMode.Noninteractive)) { if (pixel[0] != 0) { goodSelection = true; break; } } if (!goodSelection) { sel.Detach(); sel = null; } } } Pixel[] selRow = null; var whitePixel = new Pixel(255, 255, 255); for (i = 0; i < h; i++) { var imgRow = srcRgn.GetRow(srcRgn.X, srcRgn.Y + i, w); var markRow = markRgn.GetRow(markRgn.X, markRgn.Y + i, w); if (sel != null) { selRow = selRgn.GetRow(selRgn.X, selRgn.Y + i, w); } for (j = 0; j < w; j++) { var imgPixel = imgRow[j]; var markPixel = markRow[j]; int selIdx = (sel != null) ? j : 0; double iY, iI, iQ; double mY; rgb2yiq(imgPixel, out iY, out iI, out iQ); if (_useChroma) { inI[i, j] = iI; inQ[i, j] = iQ; } if (_includeOriginal) { var diff = imgPixel - markPixel;; int delta = Math.Abs(diff.Red) + Math.Abs(diff.Green) + Math.Abs(diff.Blue); } // big dirty if statement if (_pureWhite && markPixel.IsSameColor(whitePixel)) { mask[i, j] = true; } else if ((_includeOriginal && !imgPixel.IsSameColor(markPixel)) || (!_includeOriginal && markPixel.Alpha >= threshGuc)) { mask[i, j] = true; rgb2yiq(markPixel, out mY, out iI, out iQ); } else if (sel != null && selRow[selIdx].Red < threshGuc) { mask[i, j] = true; } else { mask[i, j] = false; iI = iQ = 0; } Y[i, j] = iY; I[i, j] = iI; Q[i, j] = iQ; } } if (sel != null) { sel.Detach(); } progress.Update(0.1); int n = 0; for (i = 0; i < h; i++) { for (j = 0; j < w; j++) { if (!mask[i, j]) { int min_ii = Math.Max(0, i - WindowRadius); int max_ii = Math.Min(h - 1, i + WindowRadius); int min_jj = Math.Max(0, j - WindowRadius); int max_jj = Math.Min(w - 1, j + WindowRadius); var vary = new int[WindowPixels]; var varx = new int[WindowPixels]; var var = new double[WindowPixels]; int count = 0; double sum_sq = 0; double sum = 0; double min_variance = 1.0; for (ii = min_ii; ii <= max_ii; ii++) { for (jj = min_jj; jj <= max_jj; jj++) { double val = Y[ii, jj]; sum += val; sum_sq += val * val; if (ii == i && jj == j) continue; vary[count] = i * w + j; varx[count] = ii * w + jj; var[count] = val - Y[i, j]; var[count] *= var[count]; if (_useChroma) { val = inI[ii, jj] - inI[i, j]; var[count] += val * val; val = inQ[ii, jj] - inQ[i, j]; var[count] += val * val; } if (var[count] < min_variance) min_variance = var[count]; ++count; } } double sigma = (sum_sq - (sum * sum)/(double)(count + 1)) / (double)count; if (sigma < 0.000002) sigma = 0.000002; else if (sigma < (min_variance / LN_100)) sigma = min_variance / LN_100; sum = 0; for (ii = 0; ii < count; ii++) { var[ii] = Math.Exp(-var[ii] / sigma); sum += var[ii]; } for (ii = 0; ii < count; ii++) { AI[n] = vary[ii]; AJ[n] = varx[ii]; // Fix me: just A[i, j]? A[n / (h * w) , n % (h * w)] = -var[ii] / sum; ++n; } } AI[n] = AJ[n] = i * w + j; // Fix me: just A[i, j]? A[n / (h * w), n % (h * w)] = 1.0; ++n; } } UmfPack umf = new UmfPack(); umf.Defaults(); var Ax = new double[WindowPixels, h * w]; var Ap = new int[h * w + 1]; var Ai = new int[WindowPixels * h * w]; var Map = new int[WindowPixels * h * w]; umf.TripletToCol(h * w, h * w, n, AI, AJ, A, Ap, Ai, Ax, Map); umf.Symbolic(h * w, h * w, Ap, Ai, Ax); umf.Numeric(Ap, Ai, Ax); umf.FreeSymbolic(); progress.Update(0.3); var outI = new double[h, w]; var outQ = new double[h, w]; umf.Solve(Ap, Ai, Ax, outI, I); progress.Update(0.6); umf.Solve(Ap, Ai, Ax, outQ, Q); umf.FreeNumeric(); progress.Update(0.9); for (i = 0; i < h; i++) { // FIXME: This is only for the alpha channel.. var imgRow = srcRgn.GetRow(srcRgn.X, srcRgn.Y + i, w); for (j = 0; j < w; j++) { yiq2rgb(Y[i, j], outI[i, j], outQ[i, j], imgRow[j]); } dstRgn.SetRow(imgRow, dstRgn.X, dstRgn.Y + i); } drawable.Flush(); drawable.MergeShadow(true); drawable.Update(dstRgn.X, dstRgn.Y, dstRgn.W, dstRgn.H); progress.Update(1.0); }