Kaynağa Gözat

bicubic interpolation

laurenspriem 1 yıl önce
ebeveyn
işleme
3b2fa3ba10
1 değiştirilmiş dosya ile 94 ekleme ve 1 silme
  1. 94 1
      mobile/lib/utils/image_ml_util.dart

+ 94 - 1
mobile/lib/utils/image_ml_util.dart

@@ -35,6 +35,7 @@ Color readPixelColor(
 ) {
   if (x < 0 || x >= image.width || y < 0 || y >= image.height) {
     // throw ArgumentError('Invalid pixel coordinates.');
+    log('[WARNING] `readPixelColor`: Invalid pixel coordinates, out of bounds');
     return const Color(0x00000000);
   }
   assert(byteData.lengthInBytes == 4 * image.width * image.height);
@@ -1078,7 +1079,7 @@ void warpAffineFloat32List(
       final num yOrigin = (xTrans - b00) * a10Prime + (yTrans - b10) * a11Prime;
 
       final Color pixel =
-          getPixelBilinear(xOrigin, yOrigin, inputImage, imgByteDataRgba);
+          getPixelBicubic(xOrigin, yOrigin, inputImage, imgByteDataRgba);
 
       // Set the new pixel
       outputList[startIndex + 3 * (yTrans * width + xTrans)] =
@@ -1221,6 +1222,98 @@ Color getPixelBilinear(num fx, num fy, Image image, ByteData byteDataRgba) {
   return Color.fromRGBO(r, g, b, 1.0);
 }
 
+/// Get the pixel value using Bicubic Interpolation. Code taken mainly from https://github.com/brendan-duncan/image/blob/6e407612752ffdb90b28cd5863c7f65856349348/lib/src/image/image.dart#L697
+Color getPixelBicubic(num fx, num fy, Image image, ByteData byteDataRgba) {
+  fx = fx.clamp(0, image.width - 1);
+  fy = fy.clamp(0, image.height - 1);
+
+  final x = fx.toInt() - (fx >= 0.0 ? 0 : 1);
+  final px = x - 1;
+  final nx = x + 1;
+  final ax = x + 2;
+  final y = fy.toInt() - (fy >= 0.0 ? 0 : 1);
+  final py = y - 1;
+  final ny = y + 1;
+  final ay = y + 2;
+  final dx = fx - x;
+  final dy = fy - y;
+  num cubic(num dx, num ipp, num icp, num inp, num iap) =>
+      icp +
+      0.5 *
+          (dx * (-ipp + inp) +
+              dx * dx * (2 * ipp - 5 * icp + 4 * inp - iap) +
+              dx * dx * dx * (-ipp + 3 * icp - 3 * inp + iap));
+
+  final icc = readPixelColor(image, byteDataRgba, x, y);
+
+  final ipp =
+      px < 0 || py < 0 ? icc : readPixelColor(image, byteDataRgba, px, py);
+  final icp = px < 0 ? icc : readPixelColor(image, byteDataRgba, x, py);
+  final inp = py < 0 || nx >= image.width
+      ? icc
+      : readPixelColor(image, byteDataRgba, nx, py);
+  final iap = ax >= image.width || py < 0
+      ? icc
+      : readPixelColor(image, byteDataRgba, ax, py);
+
+  final ip0 = cubic(dx, ipp.red, icp.red, inp.red, iap.red);
+  final ip1 = cubic(dx, ipp.green, icp.green, inp.green, iap.green);
+  final ip2 = cubic(dx, ipp.blue, icp.blue, inp.blue, iap.blue);
+  // final ip3 = cubic(dx, ipp.a, icp.a, inp.a, iap.a);
+
+  final ipc = px < 0 ? icc : readPixelColor(image, byteDataRgba, px, y);
+  final inc =
+      nx >= image.width ? icc : readPixelColor(image, byteDataRgba, nx, y);
+  final iac =
+      ax >= image.width ? icc : readPixelColor(image, byteDataRgba, ax, y);
+
+  final ic0 = cubic(dx, ipc.red, icc.red, inc.red, iac.red);
+  final ic1 = cubic(dx, ipc.green, icc.green, inc.green, iac.green);
+  final ic2 = cubic(dx, ipc.blue, icc.blue, inc.blue, iac.blue);
+  // final ic3 = cubic(dx, ipc.a, icc.a, inc.a, iac.a);
+
+  final ipn = px < 0 || ny >= image.height
+      ? icc
+      : readPixelColor(image, byteDataRgba, px, ny);
+  final icn =
+      ny >= image.height ? icc : readPixelColor(image, byteDataRgba, x, ny);
+  final inn = nx >= image.width || ny >= image.height
+      ? icc
+      : readPixelColor(image, byteDataRgba, nx, ny);
+  final ian = ax >= image.width || ny >= image.height
+      ? icc
+      : readPixelColor(image, byteDataRgba, ax, ny);
+
+  final in0 = cubic(dx, ipn.red, icn.red, inn.red, ian.red);
+  final in1 = cubic(dx, ipn.green, icn.green, inn.green, ian.green);
+  final in2 = cubic(dx, ipn.blue, icn.blue, inn.blue, ian.blue);
+  // final in3 = cubic(dx, ipn.a, icn.a, inn.a, ian.a);
+
+  final ipa = px < 0 || ay >= image.height
+      ? icc
+      : readPixelColor(image, byteDataRgba, px, ay);
+  final ica =
+      ay >= image.height ? icc : readPixelColor(image, byteDataRgba, x, ay);
+  final ina = nx >= image.width || ay >= image.height
+      ? icc
+      : readPixelColor(image, byteDataRgba, nx, ay);
+  final iaa = ax >= image.width || ay >= image.height
+      ? icc
+      : readPixelColor(image, byteDataRgba, ax, ay);
+
+  final ia0 = cubic(dx, ipa.red, ica.red, ina.red, iaa.red);
+  final ia1 = cubic(dx, ipa.green, ica.green, ina.green, iaa.green);
+  final ia2 = cubic(dx, ipa.blue, ica.blue, ina.blue, iaa.blue);
+  // final ia3 = cubic(dx, ipa.a, ica.a, ina.a, iaa.a);
+
+  final c0 = cubic(dy, ip0, ic0, in0, ia0).clamp(0, 255).toInt();
+  final c1 = cubic(dy, ip1, ic1, in1, ia1).clamp(0, 255).toInt();
+  final c2 = cubic(dy, ip2, ic2, in2, ia2).clamp(0, 255).toInt();
+  // final c3 = cubic(dy, ip3, ic3, in3, ia3);
+
+  return Color.fromRGBO(c0, c1, c2, 1.0);
+}
+
 List<double> getAlignedFaceBox(AlignmentResult alignment) {
   final List<double> box = [
     // [xMinBox, yMinBox, xMaxBox, yMaxBox]