[mob][photos] Clean up old dart preprocessing methods
This commit is contained in:
@@ -23,15 +23,6 @@ final _logger = Logger("ImageMlUtil");
|
||||
/// These are 8 bit unsigned integers in range 0-255 for each RGB channel
|
||||
typedef RGB = (int, int, int);
|
||||
|
||||
const gaussianKernelSize = 5;
|
||||
const gaussianKernelRadius = gaussianKernelSize ~/ 2;
|
||||
const gaussianSigma = 10.0;
|
||||
final List<List<double>> gaussianKernel =
|
||||
create2DGaussianKernel(gaussianKernelSize, gaussianSigma);
|
||||
|
||||
const maxKernelSize = gaussianKernelSize;
|
||||
const maxKernelRadius = maxKernelSize ~/ 2;
|
||||
|
||||
const List<String> supportedRustImageFormats = [
|
||||
'bmp',
|
||||
'dds',
|
||||
@@ -201,45 +192,6 @@ Future<List<Uint8List>> generateFaceThumbnailsUsingCanvas(
|
||||
}
|
||||
}
|
||||
|
||||
Future<(Float32List, Dimensions)> preprocessImageYoloFace(
|
||||
Dimensions image,
|
||||
Uint8List rawRgbaBytes,
|
||||
) async {
|
||||
const requiredWidth = 640;
|
||||
const requiredHeight = 640;
|
||||
final scale = min(requiredWidth / image.width, requiredHeight / image.height);
|
||||
final scaledWidth = (image.width * scale).round().clamp(0, requiredWidth);
|
||||
final scaledHeight = (image.height * scale).round().clamp(0, requiredHeight);
|
||||
|
||||
final processedBytes = Float32List(3 * requiredHeight * requiredWidth);
|
||||
|
||||
final buffer = Float32List.view(processedBytes.buffer);
|
||||
int pixelIndex = 0;
|
||||
const int channelOffsetGreen = requiredHeight * requiredWidth;
|
||||
const int channelOffsetBlue = 2 * requiredHeight * requiredWidth;
|
||||
for (var h = 0; h < requiredHeight; h++) {
|
||||
for (var w = 0; w < requiredWidth; w++) {
|
||||
late RGB pixel;
|
||||
if (w >= scaledWidth || h >= scaledHeight) {
|
||||
pixel = const (114, 114, 114);
|
||||
} else {
|
||||
pixel = _getPixelBilinear(
|
||||
w / scale,
|
||||
h / scale,
|
||||
image,
|
||||
rawRgbaBytes,
|
||||
);
|
||||
}
|
||||
buffer[pixelIndex] = pixel.$1 / 255;
|
||||
buffer[pixelIndex + channelOffsetGreen] = pixel.$2 / 255;
|
||||
buffer[pixelIndex + channelOffsetBlue] = pixel.$3 / 255;
|
||||
pixelIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
return (processedBytes, Dimensions(width: scaledWidth, height: scaledHeight));
|
||||
}
|
||||
|
||||
Future<Float32List> resizedToPreprocessedYoloFace(
|
||||
Uint8List rgbBytes,
|
||||
int rgbWidth,
|
||||
@@ -309,44 +261,6 @@ Future<Float32List> resizedToPreprocessedClip(
|
||||
return processedBytes;
|
||||
}
|
||||
|
||||
Future<Float32List> preprocessImageClip(
|
||||
Dimensions image,
|
||||
Uint8List rawRgbaBytes,
|
||||
) async {
|
||||
const int requiredWidth = 256;
|
||||
const int requiredHeight = 256;
|
||||
const int requiredSize = 3 * requiredWidth * requiredHeight;
|
||||
final scale = max(requiredWidth / image.width, requiredHeight / image.height);
|
||||
final bool useAntiAlias = scale < 0.8;
|
||||
final scaledWidth = (image.width * scale).round();
|
||||
final scaledHeight = (image.height * scale).round();
|
||||
final widthOffset = max(0, scaledWidth - requiredWidth) / 2;
|
||||
final heightOffset = max(0, scaledHeight - requiredHeight) / 2;
|
||||
|
||||
final processedBytes = Float32List(requiredSize);
|
||||
final buffer = Float32List.view(processedBytes.buffer);
|
||||
int pixelIndex = 0;
|
||||
const int greenOff = requiredHeight * requiredWidth;
|
||||
const int blueOff = 2 * requiredHeight * requiredWidth;
|
||||
for (var h = 0 + heightOffset; h < scaledHeight - heightOffset; h++) {
|
||||
for (var w = 0 + widthOffset; w < scaledWidth - widthOffset; w++) {
|
||||
final RGB pixel = _getPixelBilinear(
|
||||
w / scale,
|
||||
h / scale,
|
||||
image,
|
||||
rawRgbaBytes,
|
||||
antiAlias: useAntiAlias,
|
||||
);
|
||||
buffer[pixelIndex] = pixel.$1 / 255;
|
||||
buffer[pixelIndex + greenOff] = pixel.$2 / 255;
|
||||
buffer[pixelIndex + blueOff] = pixel.$3 / 255;
|
||||
pixelIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
return processedBytes;
|
||||
}
|
||||
|
||||
Future<(Float32List, List<AlignmentResult>, List<bool>, List<double>, Size)>
|
||||
preprocessToMobileFaceNetFloat32List(
|
||||
Dimensions imageDimensions,
|
||||
@@ -424,10 +338,10 @@ RGB _readPixelColor(
|
||||
Uint8List rgbaBytes,
|
||||
) {
|
||||
if (y < 0 || y >= image.height || x < 0 || x >= image.width) {
|
||||
if (y < -maxKernelRadius ||
|
||||
y >= image.height + maxKernelRadius ||
|
||||
x < -maxKernelRadius ||
|
||||
x >= image.width + maxKernelRadius) {
|
||||
if (y < -2 ||
|
||||
y >= image.height + 2 ||
|
||||
x < -2 ||
|
||||
x >= image.width + 2) {
|
||||
_logger.severe(
|
||||
'`readPixelColor`: Invalid pixel coordinates, out of bounds. x: $x, y: $y',
|
||||
);
|
||||
@@ -445,29 +359,6 @@ RGB _readPixelColor(
|
||||
);
|
||||
}
|
||||
|
||||
RGB _getPixelBlurred(
|
||||
int x,
|
||||
int y,
|
||||
Dimensions image,
|
||||
Uint8List rgbaBytes,
|
||||
) {
|
||||
double r = 0, g = 0, b = 0;
|
||||
for (int ky = 0; ky < gaussianKernelSize; ky++) {
|
||||
for (int kx = 0; kx < gaussianKernelSize; kx++) {
|
||||
final int px = (x - gaussianKernelRadius + kx);
|
||||
final int py = (y - gaussianKernelRadius + ky);
|
||||
|
||||
final RGB pixelRgbTuple = _readPixelColor(px, py, image, rgbaBytes);
|
||||
final double weight = gaussianKernel[ky][kx];
|
||||
|
||||
r += pixelRgbTuple.$1 * weight;
|
||||
g += pixelRgbTuple.$2 * weight;
|
||||
b += pixelRgbTuple.$3 * weight;
|
||||
}
|
||||
}
|
||||
return (r.round(), g.round(), b.round());
|
||||
}
|
||||
|
||||
List<List<int>> _createGrayscaleIntMatrixFromNormalized2List(
|
||||
Float32List imageList,
|
||||
int startIndex, {
|
||||
@@ -615,52 +506,6 @@ Future<Uint8List> _cropAndEncodeCanvas(
|
||||
return await _encodeImageToPng(croppedImage);
|
||||
}
|
||||
|
||||
RGB _getPixelBilinear(
|
||||
num fx,
|
||||
num fy,
|
||||
Dimensions image,
|
||||
Uint8List rawRgbaBytes, {
|
||||
bool antiAlias = false,
|
||||
}) {
|
||||
// Clamp to image boundaries
|
||||
fx = fx.clamp(0, image.width - 1);
|
||||
fy = fy.clamp(0, image.height - 1);
|
||||
|
||||
// Get the surrounding coordinates and their weights
|
||||
final int x0 = fx.floor();
|
||||
final int x1 = fx.ceil();
|
||||
final int y0 = fy.floor();
|
||||
final int y1 = fy.ceil();
|
||||
final dx = fx - x0;
|
||||
final dy = fy - y0;
|
||||
final dx1 = 1.0 - dx;
|
||||
final dy1 = 1.0 - dy;
|
||||
|
||||
// Get the original pixels (with gaussian blur if antialias)
|
||||
final RGB Function(int, int, Dimensions, Uint8List) readPixel =
|
||||
antiAlias ? _getPixelBlurred : _readPixelColor;
|
||||
final RGB pixel1 = readPixel(x0, y0, image, rawRgbaBytes);
|
||||
final RGB pixel2 = readPixel(x1, y0, image, rawRgbaBytes);
|
||||
final RGB pixel3 = readPixel(x0, y1, image, rawRgbaBytes);
|
||||
final RGB pixel4 = readPixel(x1, y1, image, rawRgbaBytes);
|
||||
|
||||
int bilinear(
|
||||
num val1,
|
||||
num val2,
|
||||
num val3,
|
||||
num val4,
|
||||
) =>
|
||||
(val1 * dx1 * dy1 + val2 * dx * dy1 + val3 * dx1 * dy + val4 * dx * dy)
|
||||
.round();
|
||||
|
||||
// Calculate the weighted sum of pixels
|
||||
final int r = bilinear(pixel1.$1, pixel2.$1, pixel3.$1, pixel4.$1);
|
||||
final int g = bilinear(pixel1.$2, pixel2.$2, pixel3.$2, pixel4.$2);
|
||||
final int b = bilinear(pixel1.$3, pixel2.$3, pixel3.$3, pixel4.$3);
|
||||
|
||||
return (r, g, b);
|
||||
}
|
||||
|
||||
/// 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
|
||||
RGB _getPixelBicubic(
|
||||
num fx,
|
||||
@@ -763,31 +608,4 @@ RGB _getPixelBicubic(
|
||||
// final c3 = cubic(dy, ip3, ic3, in3, ia3);
|
||||
|
||||
return (c0, c1, c2); // (red, green, blue)
|
||||
}
|
||||
|
||||
List<List<double>> create2DGaussianKernel(int size, double sigma) {
|
||||
final List<List<double>> kernel =
|
||||
List.generate(size, (_) => List<double>.filled(size, 0));
|
||||
double sum = 0.0;
|
||||
final int center = size ~/ 2;
|
||||
|
||||
for (int y = 0; y < size; y++) {
|
||||
for (int x = 0; x < size; x++) {
|
||||
final int dx = x - center;
|
||||
final int dy = y - center;
|
||||
final double g = (1 / (2 * pi * sigma * sigma)) *
|
||||
exp(-(dx * dx + dy * dy) / (2 * sigma * sigma));
|
||||
kernel[y][x] = g;
|
||||
sum += g;
|
||||
}
|
||||
}
|
||||
|
||||
// Normalize the kernel
|
||||
for (int y = 0; y < size; y++) {
|
||||
for (int x = 0; x < size; x++) {
|
||||
kernel[y][x] /= sum;
|
||||
}
|
||||
}
|
||||
|
||||
return kernel;
|
||||
}
|
||||
}
|
||||
@@ -415,9 +415,9 @@ Future<MLResult> analyzeImageStatic(Map args) async {
|
||||
if (decodeInRust) {
|
||||
rustResults = await processImageMlFromPath(imagePath: imagePath);
|
||||
} else {
|
||||
final (image, rawRgbaBytes) = await decodeImageFromPath(imagePath);
|
||||
final (image, decodedRgbaBytes) = await decodeImageFromPath(imagePath);
|
||||
rustResults = await processImageMlFromData(
|
||||
rgbaData: rawRgbaBytes,
|
||||
rgbaData: decodedRgbaBytes,
|
||||
width: image.width,
|
||||
height: image.height,
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user