How do I get the RGB values from an image in Flutter? - flutter

I'm creating a mobile client for my object-detection server. I already have a perfectly-working python client which takes an image as input, sends it to the server in an HTTP request and receives prediction as a json response. I'm trying to achieve the same in Dart which I'm fairly new to.
The python code I have converts the input JPG image into a numpy array of RGB values in the following format (using a 5x4 image as an example)-
[
[[182, 171, 153], [203, 188, 169], [242, 214, 200], [255, 235, 219], [155, 111, 98]],
[[181, 171, 146], [204, 190, 164], [255, 237, 214], [177, 142, 120], [84, 42, 20]],
[[176, 168, 129], [218, 206, 166], [180, 156, 118], [91, 59, 21], [103, 64, 25]],
[[186, 180, 132], [166, 156, 107], [91, 68, 24], [94, 63, 17], [122, 84, 39]]
]
In my dart code, I have attempted to convert the image into a list of 8-bit unsigned integers using-
Uint8List inputImg = (await rootBundle.load("assets/test.jpg")).buffer.asUint8List()
It gives me a long array of over 800 ints for the same 5x4 image.
On testing it with two single-pixel images (one black and one white), a large section of the Uint8List seems to be repeating for each. I isolated the differing sections of the array and they do not correspond with the RGB values expected for the colors (I expected [0 0 0] and [255 255 255], but got something like 255, 0, 63, 250, 0, 255, 0 and 254, 254, 40, 3 for the two respectively)
I just need the RGB values in the image. Would appreciate someone pointing me in the right direction!

Images are normally compressed when they're stored. Based on the file extension, I'm guessing you're using JPEG encoding. This means the data stored in the assets/test.jpg file is not an array of colors. That would be an inefficient use of data storage if everything were done that way. To get that array of colors, you need to decode the image. This can be done with the image package.
To do this, first add the package as a dependency by adding the following to the pubspec.yaml:
dependencies:
image: ^3.0.4
You should follow the same method of obtaining the encoded image data. But you then need to decode it.
final Uint8List inputImg = (await rootBundle.load("assets/test.jpg")).buffer.asUint8List();
final decoder = JpegDecoder();
final decodedImg = decoder.decodeImage(inputImg);
final decodedBytes = decodedImg.getBytes(format: Format.rgb);
decodedBytes contains a single depth list of all your pixel values in RGB format. To get it into your desired format, just loop over the values and add them to a new list.
List<List<List<int>> imgArr = [];
for(int y = 0; y < decodedImage.height; y++) {
imgArr.add([]);
for(int x = 0; x < decodedImage.width; x++) {
int red = decodedBytes[y*decodedImage.width*3 + x*3];
int green = decodedBytes[y*decodedImage.width*3 + x*3 + 1];
int blue = decodedBytes[y*decodedImage.width*3 + x*3 + 2];
imgArr[y].add([red, green, blue]);
}
}

To do this, first add the package as a dependency by adding the following to the pubspec.yaml:
image: ^3.2.0
import image library to your file:
import 'package:image/image.dart' as im;
get brightness of image:
int getBrightness(File file) {
im.Image? image = im.decodeImage(file.readAsBytesSync());
final data = image?.getBytes();
var color= 0;
for (var x = 0; x < data!.length; x += 4) {
final int r = data[x];
final int g = data[x + 1];
final int b = data[x + 2];
final int avg = ((r + g + b) / 3).floor();
color += avg;
}
return (color/ (image!.width * image.height)).floor();
}
Check selected image is dark or light:
bool isImageDark(int brightness) {
return brightness <= 127;
}
Use above method like this:
int brightness = getBrightness(file);
bool isDark= isImageDark(brightness);
Now you can change your icon color based on your background image

Related

How can i get finger-prints through image using flutter

i am using opencv package https://pub.dev/packages/opencv_4 but can not get fingertprints clearly from image.
i am using this function.
Uint8List? _byte = await Cv2.morphologyEx(
pathFrom: CVPathFrom.GALLERY_CAMERA,
pathString: photoFinger.path,
operation: Cv2.COLOR_BayerGB2RGB ,
kernelSize: [30, 30],
);
i have python code using openvcv lib but dont know how to convert it into dart. using openCv dart package.
python code is:
import cv2
# Read the input image
img = cv2.imread('input_image.jpg', cv2.IMREAD_GRAYSCALE)
# Apply Gaussian blur to remove noise
img = cv2.GaussianBlur(img, (5, 5), 0)
# Apply adaptive thresholding to segment the fingerprint
img = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY_INV, 11, 5)
# Apply morphological operations to remove small objects and fill in gaps
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))
img = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel, iterations=1)
img = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel, iterations=1)
# Estimate the orientation field of the fingerprint
sobel_x = cv2.Sobel(img, cv2.CV_32F, 1, 0, ksize=3)
sobel_y = cv2.Sobel(img, cv2.CV_32F, 0, 1, ksize=3)
theta = cv2.phase(sobel_x, sobel_y)
# Apply non-maximum suppression to thin the ridges
theta_quantized = np.round(theta / (np.pi / 8)) % 8
thin = cv2.ximgproc.thinning(img, thinningType=cv2.ximgproc.THINNING_ZHANGSUEN, thinningIterations=5)
# Extract minutiae points from the fingerprint
minutiae = cv2.ximgproc.getFastFeatureDetector().detect(thin)
# Display the output image with minutiae points
img_with_minutiae = cv2.drawKeypoints(img, minutiae, None, color=(0, 255, 0), flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
cv2.imshow('Output Image', img_with_minutiae)
cv2.waitKey(0)
cv2.destroyAllWindows()

Tflite with Flutter - TensorBuffer to (Tensor)Image

I did a segmentation with the tflite library for flutter and it works fine, I load the model, make an RGB [3, 224, 224] input and run it through the interpreter of the tflite_flutter_helper library.
But how to convert the output of my model, [1, 1, 224, 224] back to a TensorImage or an Image in general? When I run
TensorImage resultImage = TensorImage.fromTensorBuffer(tensorBuffer);
or
TensorImage resultImage = TensorImage(tensorBuffer.getDataType());
resultImage.loadTensorBuffer(tensorBuffer);
I get the error message:
The shape of a RGB image should be (h, w, c) or (1, h, w, c), and channels representing R, G, B in order. The provided image shape is [1, 224, 224, 1]
I tried solving it by rearranging my output to the shape of (1, h, w, c) like shown in the error to [1, 224, 224, 1], but I get the same result. Heres my full code:
ImageProcessor imageProcessor = ImageProcessorBuilder()
.add(ResizeOp(224, 224, ResizeMethod.NEAREST_NEIGHBOUR))
.add(NormalizeOp(127.5, 127.5))
.build();
SequentialProcessor<TensorBuffer> probabilityProcessor = TensorProcessorBuilder().add(DequantizeOp(0, 1 / 255)).build();
TensorImage tensorImage = TensorImage(TfLiteType.float32);
tensorImage.loadImage(img.Image.fromBytes(224, 224, image.readAsBytesSync()));
tensorImage = imageProcessor.process(tensorImage);
TensorBuffer tensorBuffer;
try{
Interpreter interpreter = await Interpreter.fromAsset('models/enet.tflite');
tensorBuffer = TensorBuffer.createFixedSize(interpreter.getOutputTensor(0).shape, interpreter.getOutputTensor(0).type);
interpreter.run(tensorImage.buffer, tensorBuffer.getBuffer());
tensorBuffer = probabilityProcessor.process(tensorBuffer);
// ignore: invalid_use_of_protected_member
tensorBuffer.resize(List<int>.of([1, 224, 224, 1]));
TensorImage resultImage = TensorImage(tensorBuffer.getDataType());
resultImage.loadTensorBuffer(tensorBuffer);
}catch(e){
print('Error loading model: ' + e.toString());
}
I furthermore tried reading in the buffer from the tensorBuffer directly into a Image of flutter via
Image result = Image.memory(tensorBuffer.getBuffer().asUint8List());
with an invalid imae data exception as a result.
**** EDIT ****
I also tried the ImageConversions class from tflite_flutter_helper with
img.Image resultImage = ImageConversions.convertGrayscaleTensorBufferToImage(tensorBuffer);
but still no success...

Converting grayscale 1D list of Image Pixels to Grayscale Image Dart

I am trying to convert a binary mask predicted with the pytorch_mobile package to an image I can show in my app.
The Prediction I receive is a 1-Dimensional list containing the predictions that my model spits out, these are negative for pixels assigned to the background and positive for pixels assigned to the area of interest. After this, I create a list that assigns the value 0 to all previously negative values, and 255 to all previously positive values yielding a 1-Dimensional list containing the values 0 or 255 depending on what the pixel was classified as.
The image prediction is a size of 512x512 pixels, and the length of the list is subsequently 262,144.
How would I be able to convert this list into an image that I could save to storage or show via the flutter UI?
Here is my current code:
customModel = await PyTorchMobile
.loadModel('assets/segmentation_model.pt');
result_list = [];
File image = File(filePath);
List prediction = await customModel.getImagePredictionList(image, 512, 512);
prediction.forEach((element) {
if (element >0){
result_list.add(255);
}else if(element <= 0){
result_list.add(0);
}
});
result_list_Uint8 = Uint8List.fromList(result_list);
The following should do the trick. Just use Image.setPixelSafe to set every pixel in the image and then convert it to a Flutter Image widget with encodePng and Image.memory.
import 'package:image/image.dart' as im;
...
final img = im.Image(512, 512);
for (var i = 0, len = 512; i < len; i++) {
for (var j = 0, len = 512; j < len; j++) {
final color = result_list_Uint8[i * 512 + j] == 0 ? 0 : 0xffffff;
img.setPixelSafe(i, j, 0xff000000 | color);
}
}
final pngBytes = Uint8List.fromList(im.encodePng(img));
photoImage = Image.memory(pngBytes);

Combining image channels in CImg

In CImg, I have split an RGBA image apart into multiple single-channel images, with code like:
CImg<unsigned char> input("foo.png");
CImg<unsigned char> r = input.get_channel(0), g = input.get_channel(1), b = input.get_channel(2), a = input.get_channel(3);
Then I try to swizzle the channel order:
CImg<unsigned char> output(input.width(), input.height(), 1, input.channels());
output.channel(0) = g;
output.channel(1) = b;
output.channel(2) = r;
output.channel(3) = a;
When I save the image out, however, it turns out grayscale, apparently based on the alpha channel value; for example, this input:
becomes this output:
How do I specify the image color format so that CImg saves into the correct color space?
Simply copying a channel does not work like that; a better approach is to copy the pixel data with std::copy:
std::copy(g.begin(), g.end(), &output.atX(0, 0, 0, 0));
std::copy(b.begin(), b.end(), &output.atX(0, 0, 0, 1));
std::copy(r.begin(), r.end(), &output.atX(0, 0, 0, 2));
std::copy(a.begin(), a.end(), &output.atX(0, 0, 0, 3));
This results in an output image like:

Flutter: Convert color temperature to RGB

I am looking for a way to convert a color temperature to its approximate RGB color in Flutter.
If you have a look at this website, a color temperature of 1800 equals some kind of orange:
Is there a convenient way to do this in Flutter? The website I found seems to have hardcoded the colors. Providing me with a formula would also be appreaciated.
This blog has a formula available in several languages. Below is my port to Dart/Flutter.
Color colorTempToRGB(double colorTemp) {
final temp = colorTemp / 100;
final red = temp <= 66
? 255
: (pow(temp - 60, -0.1332047592) * 329.698727446).round().clamp(0, 255);
final green = temp <= 66
? (99.4708025861 * log(temp) - 161.1195681661).round().clamp(0, 255)
: (pow(temp - 60, -0.0755148492) * 288.1221695283).round().clamp(0, 255);
final blue = temp >= 66
? 255
: temp <= 19
? 0
: (138.5177312231 * log(temp - 10) - 305.0447927307)
.round()
.clamp(0, 255);
return Color.fromARGB(255, red, green, blue);
}