refactoring code to use proper views in the UI and turned the camera instance into its own view with callbacks.
Also added in the model for initial use, and working to create the inferences off of TFLite using that view.
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:camera/camera.dart';
|
||||
import 'package:image/image.dart' as image_lib;
|
||||
import 'package:logger/logger.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
|
||||
import 'logger.dart';
|
||||
|
||||
/// ImageUtils
|
||||
class ImageUtils {
|
||||
/// Converts a [CameraImage] in YUV420 format to [image_lib.Image] in RGB format
|
||||
static image_lib.Image? convertCameraImage(CameraImage cameraImage) {
|
||||
if (cameraImage.format.group == ImageFormatGroup.yuv420) {
|
||||
return convertYUV420ToImage(cameraImage);
|
||||
} else if (cameraImage.format.group == ImageFormatGroup.bgra8888) {
|
||||
return convertBGRA8888ToImage(cameraImage);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts a [CameraImage] in BGRA888 format to [image_lib.Image] in RGB format
|
||||
static image_lib.Image convertBGRA8888ToImage(CameraImage cameraImage) {
|
||||
image_lib.Image img = image_lib.Image.fromBytes(
|
||||
cameraImage.planes[0].width ?? 0,
|
||||
cameraImage.planes[0].height ?? 0,
|
||||
cameraImage.planes[0].bytes,
|
||||
format: image_lib.Format.bgra
|
||||
);
|
||||
return img;
|
||||
}
|
||||
|
||||
/// Converts a [CameraImage] in YUV420 format to [image_lib.Image] in RGB format
|
||||
static image_lib.Image convertYUV420ToImage(CameraImage cameraImage) {
|
||||
final int width = cameraImage.width;
|
||||
final int height = cameraImage.height;
|
||||
|
||||
final int uvRowStride = cameraImage.planes[1].bytesPerRow;
|
||||
final int uvPixelStride = cameraImage.planes[1].bytesPerPixel?? 0;
|
||||
|
||||
final image = image_lib.Image(width, height);
|
||||
|
||||
for (int w = 0; w < width; w++) {
|
||||
for (int h = 0; h < height; h++) {
|
||||
final int uvIndex =
|
||||
uvPixelStride * (w / 2).floor() + uvRowStride * (h / 2).floor();
|
||||
final int index = h * width + w;
|
||||
|
||||
final y = cameraImage.planes[0].bytes[index];
|
||||
final u = cameraImage.planes[1].bytes[uvIndex];
|
||||
final v = cameraImage.planes[2].bytes[uvIndex];
|
||||
|
||||
image.data[index] = ImageUtils.yuv2rgb(y, u, v);
|
||||
}
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
/// Convert a single YUV pixel to RGB
|
||||
static int yuv2rgb(int y, int u, int v) {
|
||||
// Convert yuv pixel to rgb
|
||||
int r = (y + v * 1436 / 1024 - 179).round();
|
||||
int g = (y - u * 46549 / 131072 + 44 - v * 93604 / 131072 + 91).round();
|
||||
int b = (y + u * 1814 / 1024 - 227).round();
|
||||
|
||||
// Clipping RGB values to be inside boundaries [ 0 , 255 ]
|
||||
r = r.clamp(0, 255);
|
||||
g = g.clamp(0, 255);
|
||||
b = b.clamp(0, 255);
|
||||
|
||||
return 0xff000000 |
|
||||
((b << 16) & 0xff0000) |
|
||||
((g << 8) & 0xff00) |
|
||||
(r & 0xff);
|
||||
}
|
||||
|
||||
static void saveImage(image_lib.Image image, [int i = 0]) async {
|
||||
List<int> jpeg = image_lib.JpegEncoder().encodeImage(image);
|
||||
final appDir = await getTemporaryDirectory();
|
||||
final appPath = appDir.path;
|
||||
final fileOnDevice = File('$appPath/out$i.jpg');
|
||||
await fileOnDevice.writeAsBytes(jpeg, flush: true);
|
||||
logger.i('Saved $appPath/out$i.jpg');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user