private static VBox[] MedianCutApply(IReadOnlyList <int> histo, VBox vbox) { switch (vbox.Count(false)) { case 0: return(null); case 1: return(new[] { vbox.Clone(), null }); } // only one pixel, no split var rw = vbox.R2 - vbox.R1 + 1; var gw = vbox.G2 - vbox.G1 + 1; var bw = vbox.B2 - vbox.B1 + 1; var maxw = Math.Max(Math.Max(rw, gw), bw); // Find the partial sum arrays along the selected axis. var total = 0; var partialsum = new int[VboxLength]; // -1 = not set / 0 = 0 partialsum.Fill(-1); // -1 = not set / 0 = 0 var lookaheadsum = new int[VboxLength]; lookaheadsum.Fill(-1); int i, j, k, sum, index; if (maxw == rw) { for (i = vbox.R1; i <= vbox.R2; i++) { sum = 0; for (j = vbox.G1; j <= vbox.G2; j++) { for (k = vbox.B1; k <= vbox.B2; k++) { index = GetColorIndex(i, j, k); sum += histo[index]; } } total += sum; partialsum[i] = total; } } else if (maxw == gw) { for (i = vbox.G1; i <= vbox.G2; i++) { sum = 0; for (j = vbox.R1; j <= vbox.R2; j++) { for (k = vbox.B1; k <= vbox.B2; k++) { index = GetColorIndex(j, i, k); sum += histo[index]; } } total += sum; partialsum[i] = total; } } else /* maxw == bw */ { for (i = vbox.B1; i <= vbox.B2; i++) { sum = 0; for (j = vbox.R1; j <= vbox.R2; j++) { for (k = vbox.G1; k <= vbox.G2; k++) { index = GetColorIndex(j, k, i); sum += histo[index]; } } total += sum; partialsum[i] = total; } } for (i = 0; i < VboxLength; i++) { if (partialsum[i] != -1) { lookaheadsum[i] = total - partialsum[i]; } } // determine the cut planes return(maxw == rw ? DoCut('r', vbox, partialsum, lookaheadsum, total) : maxw == gw ? DoCut('g', vbox, partialsum, lookaheadsum, total) : DoCut('b', vbox, partialsum, lookaheadsum, total)); }
private static VBox[] DoCut( char color, VBox vbox, IReadOnlyList <int> partialsum, IReadOnlyList <int> lookaheadsum, int total) { int vboxDim1; int vboxDim2; switch (color) { case 'r': vboxDim1 = vbox.R1; vboxDim2 = vbox.R2; break; case 'g': vboxDim1 = vbox.G1; vboxDim2 = vbox.G2; break; default: vboxDim1 = vbox.B1; vboxDim2 = vbox.B2; break; } for (var i = vboxDim1; i <= vboxDim2; i++) { if (partialsum[i] > total / 2) { var vbox1 = vbox.Clone(); var vbox2 = vbox.Clone(); var left = i - vboxDim1; var right = vboxDim2 - i; var d2 = left <= right ? Math.Min(vboxDim2 - 1, ~~(i + right / 2)) : Math.Max(vboxDim1, ~~((int)(i - 1 - left / 2.0))); // avoid 0-count boxes while (d2 < 0 || partialsum[d2] <= 0) { d2++; } var count2 = lookaheadsum[d2]; while (count2 == 0 && d2 > 0 && partialsum[d2 - 1] > 0) { count2 = lookaheadsum[--d2]; } // set dimensions switch (color) { case 'r': vbox1.R2 = d2; vbox2.R1 = d2 + 1; break; case 'g': vbox1.G2 = d2; vbox2.G1 = d2 + 1; break; default: vbox1.B2 = d2; vbox2.B1 = d2 + 1; break; } return(new[] { vbox1, vbox2 }); } } throw new Exception("VBox can't be cut"); }