|
@@ -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]
|