Image to RGB matrix in flutter - flutter

I am a beginner in Flutter. I want to choose an image from my local and convert it into an RGB array. Can anybody please provide me with the code to do so correctly?

You can use this package - image
It provides image conversion and manipulation utility functions.
import 'package:image/image.dart' as Imagi;
Here's how to use it to obtain RGB matrix of a file from ImagePicker()-
final image = await ImagePicker().pickImage(source: ImageSource.gallery);
if (image == null) return;
final imageTemp = File(image.path);
controlImage = imageTemp;
Now here's a function for obtaining the RGB matrix -
List<List<int>> imgArray = [];
void readImage() async{
final bytes = await controlImage!.readAsBytes();
final decoder = Imagi.JpegDecoder();
final decodedImg = decoder.decodeImage(bytes);
final decodedBytes = decodedImg!.getBytes(format: Imagi.Format.rgb);
// print(decodedBytes);
print(decodedBytes.length);
// int loopLimit = decodedImg.width;
int loopLimit =1000;
for(int x = 0; x < loopLimit; x++) {
int red = decodedBytes[decodedImg.width*3 + x*3];
int green = decodedBytes[decodedImg.width*3 + x*3 + 1];
int blue = decodedBytes[decodedImg.width*3 + x*3 + 2];
imgArray.add([red, green, blue]);
}
print(imgArray);
}
The array imgArray will contain the RGB matrix

Related

Dart Fails to save Bytes to PNG, JPEG

I have been trying for hours to figure out why my code is not working. Basically, I have an image. I load its bytes into dart as a list of Uint8List. Then, I replace the values of the list with some other values. The problem is that after replacing the values, when I call the File().writeAsBytes() function, the image is CORRUPTED. Don't know why this is happening. Tried doing everything I could.
var b = File("assets/1K91k (1).jpg").readAsBytesSync();
void main() {
runApp(const MyApp());
for (int i = 0; i < b.length; i++) {
double check = b[i] / 255;
if (check > 0.8) {
b[i] = 255;
} else {
b[i] = 2;
}
}
File("/home/kq1231/Desktop/test.jpg")
..createSync()
..writeAsBytesSync(b);
}
I tried converting the b list to a Uint8List but to no avail.
Feels funny to answer my own question but here's how it got working:
import 'package:image/image.dart' as image;
import 'dart:io';
image.Image prettify(String fileName, String exportPath, String imageName,
double threshold, int blurRadius) {
var b = image.decodeImage(File(fileName).readAsBytesSync());
b = image.gaussianBlur(b!, blurRadius);
for (int i = 0; i < b.width; i++) {
for (int j = 0; j < b.height; j++) {
var pix = b.getPixel(i, j);
if ((image.getBlue(pix) + image.getRed(pix) + image.getGreen(pix)) /
(255 * 3) >
threshold) {
b.setPixel(i, j, 0xffffff);
} else {
b.setPixel(i, j, 0);
}
}
}
File("$exportPath/$imageName")
..createSync()
..writeAsBytesSync(image.encodePng(b));
return b;
}
This is a function called prettify. It applies a specific operation to a given image. First, decode the image. Then, loop through each pixel, average the R, G and B values to get the grayscale value (get the value of the pixel using image.getPixel() and set its value using image.setPixel()). Then, encode it back to .png format and save it.
Note that image is the name of the library imported.

How to split a list into sublists using flutter?

I'm new with flutter.
I have data in txt file I retrieve it, then, I convert it into list and finally I split this list into sublists. Every sublist contains 19 values.
It's okey for this part. But now, the problem is that in the end of file we could have less than 19 values. So my question is how to add this values to another sublist also.
Actually, those sublists contains hexadecimals values, I was thinking about filling the last sublist with zeros until we have 19 values.But, I don't know how to do this.
Or, if you have any other solution to fix this issue?
this is my code:
static Future<List> localPath() async {
File textasset = File('/storage/emulated/0/RPSApp/assets/bluetooth.txt');
final text = await textasset.readAsString();
final bytes =
text.split(',').map((s) => s.trim()).map((s) => int.parse(s)).toList();
final chunks = [];
//final list4 = [];
int chunkSize = 19;
for (int i = 0; i < 40; i += chunkSize) {
chunks.add(bytes.sublist(
i, i + chunkSize > bytes.length ? bytes.length : i + chunkSize));
}
return chunks;
}
Thanks in advance for your help
import 'package:collection/collection.dart'; // add to your pubspec
final newList = originalList.slices(19).toList();
Done. Read the documentation for details.
Edit: After reading your comment, I came up with this:
import 'dart:math';
import 'package:collection/collection.dart';
void main(List<String> arguments) {
final random = Random();
const chunkSize = 7;
final source = List.generate(100, (index) => random.nextInt(100) + 1);
List<int> padTo(List<int> input, int count) {
return [...input, ...List.filled(count - input.length, 0)];
}
List<int> padToChunksize(List<int> input) => padTo(input, chunkSize);
final items = source.slices(chunkSize).map(padToChunksize).toList();
print(items);
}
which demonstrates how to pad each short list with more 0's.

Mask out color in Image canvas flutter

I am trying to add skin tone to an image in flutter canvas.
I've used the following code before to apply chroma by altering pixels when I load the image:
static Future<ui.Image> applyChromaToImage(ui.Image image, String pathForImage, RGBPixel chromaToApply, {RGBPixel previousChromaColor}) async
{
List<ChromaPointRange> chromaPoints = processChromaImageBytes(
image, imgBytes);
for(ChromaPointRange rnge in chromaPoints)
{
for(int y = rnge.yValStart; y <= rnge.yValEnd; y++)
{
RGBPixel currentPixel = RGBPixel.generatePixelFromImagePos(imgBytes, image.width, rnge.xVal, y);
//replace current pixel with skin tone
RGBPixel newPixl = currentPixel.mergeSkinTonePixel(chromaToApply, previousChromaColor);
imgBytes.setUint32((y * image.width + rnge.xVal) * 4, newPixl.getHex());
}
}
final Completer<ui.Image> imageCompleter = new Completer();
//looks the endian format doesn't get set right here
ui.PixelFormat formatToUse = Endian.host == Endian.little ? ui.PixelFormat.rgba8888 : ui.PixelFormat.bgra8888;
ui.decodeImageFromPixels(
imgBytes.buffer.asUint8List(),
image.width,
image.height,
formatToUse,
(ui.Image result) {
imageCompleter.complete(result);
// use your result image
},
);
//return image;
return await imageCompleter.future;
}
static List<ChromaPointRange> processChromaImageBytes(ui.Image image, ByteData imgBytes)
{
List<ChromaPointRange> chromaPoints = [];
ChromaPointRange currentPoints = null;
for(int x = 0; x < image.width; x = x + 1)
{
for(int y = 0; y < image.height; y = y + 1)
{
RGBPixel currentPixel = RGBPixel.generatePixelFromImagePos(imgBytes, image.width, x, y);
if(currentPixel.isSkinTonePixel())
{
if(currentPoints == null)
{
currentPoints = ChromaPointRange.fromEmpty();
currentPoints.xVal = x;
currentPoints.yValStart = y;
}
}
else if(currentPoints != null)
{
currentPoints.yValEnd = y - 1;
chromaPoints.add(currentPoints);
currentPoints = null;
}
}
if(currentPoints != null)
{
currentPoints.yValEnd = image.height - 1;
chromaPoints.add(currentPoints);
currentPoints = null;
}
}
return chromaPoints;
}
which basically checks every pixel in the image to see if it's within a range of the target color ( with is RGB 0, 255, 0), then adjusts the pixel if it is. This works, but takes a really long time ~ 3 seconds for a 1920 x 1080 image.
The end result is that I want to paint the image to a canvas with a skin tone applied. I've tried a different strategy, by painting the color underneath the image, and then trying to mask out that color from the image using canvas color filters. This is 1000% faster, but doesn't quite work.
Here is the code:
renderSprite(Canvas canvasToRender, Offset offsetToRender)
{
Paint imgPaint = new Paint();
if(chromaToApply != null)
{
Paint chromaPaint = new Paint();
chromaPaint.colorFilter = ColorFilter.mode(Color.fromRGBO(chromaToApply.redVal, chromaToApply.greenVal, chromaToApply.blueVal, 1), BlendMode.modulate);
canvasToRender.drawImage(spriteImage, offsetToRender, chromaPaint);
imgPaint.colorFilter = ColorFilter.mode(Color.fromRGBO(0, 255, 0, 1), BlendMode.dstOut);
}
if(spriteImage != null)
canvasToRender.drawImage(spriteImage, offsetToRender, imgPaint);
}
Here is the image that is painted underneath
Here is the image that is painted ontop
So I'm trying to mask out the green so the tan skin tone shows through on specific parts of the image.
I can't seem to find any combination of ColorFilter or anything else that will mask out the green color for me from the canvas. Any suggestions?

Converting matrix of colors to image in flutter

I need to convert List<List<int>>> to an dart:ui.Image. I have an algorithm to convert an integer to a color. I tried to do this by drawing one-pixel rectangles on the dart:ui.Canvas, but it is about 100 times slower than I expected! _getPixelColor is the method by which I convert int to Color. Here is my code:
Future<void> matrixToImage(FField sourceMatrix) async {
PictureRecorder p = PictureRecorder();
Canvas c = Canvas(
p,
Rect.fromLTWH(0, 0, sourceMatrix.length.toDouble(),
sourceMatrix[0].length.toDouble()));
Paint paint = Paint();
for (int x = 0; x < sourceMatrix.length; x++) {
for (int y = 0; y < sourceMatrix[0].length; y++) {
int pixelValue = sourceMatrix[x][y];
paint.color = _getPixelColor(pixelValue / 40 / paletteLength + paletteOffset);
c.drawRect(Rect.fromLTWH(x.toDouble(), y.toDouble(), 1, 1), paint);
}
}
Picture picture = p.endRecording();
Image result = await picture.toImage(sourceMatrix.length, sourceMatrix[0].length);
}
If you can compute your int value to an int value that the Image class understands, you don't need the detour through canvas drawing.
Just use Image.fromBytes with the .value of the Color as the list of ints.
That depends on how the image data is stored in the list of INTs.
Generally, I like this package to manipulate images and display them:
https://pub.dev/packages/image
import 'package:image/image.dart' as im;
im.Image? img = decodeImage(bytes); // different-IMAGE class !
Uint8List uint8list = getEncodedJpg(img!,quality: 85) as Uint8List;
// ...
build(BuildContext context) {
return Container(child:
Image.memory(uint8list) // material-IMAGE class !
);
}

Calculate Average Color from a SVG Image (SvgPicture.network(""))

I try to calculate the average color from SVG format Image, but I don't know how can an SVG Image from the network convert to Unit8List, ImageProvider, or BitMap!
for any of these types that I say, I can calculate the average color with the below code :
(I use image package)
import 'package:image/image.dart' as imgPack;
//
Unit8List _myHunit8List = ...
imgPack.Image bitmap = imgPack.decodeImage(_myHunit8List );
int redBucket = 0;
int greenBucket = 0;
int blueBucket = 0;
int pixelCount = 0;
for (int y = 0; y < bitmap.height; y++) {
for (int x = 0; x < bitmap.width; x++) {
int c = bitmap.getPixel(x, y);
pixelCount++;
redBucket += img.getRed(c);
greenBucket += img.getGreen(c);
blueBucket += img.getBlue(c);
}
}
Color averageColor = Color.fromRGBO(redBucket ~/ pixelCount,
greenBucket ~/ pixelCount, blueBucket ~/ pixelCount, 1);
how can I an SVG Image from the network
( I use flutter_svg package like:
SvgPicture.network(url);
) convert to Unit8List ?
It transfers from Image url to Uint8List.
Future<Uint8List> getUint8ListFromImage(imgUrl) async {
Uint8List bytes = (await NetworkAssetBundle(Uri.parse(imgUrl)).load(imgUrl))
.buffer
.asUint8List();
print(bytes);
return bytes;
}
you can convert network image to file and then you can easily convert file to uint8List,
convert image url to file
Future<File> urlToFile(String imageUrl) async {
// generate random number.
var rng = new Random();
// get temporary directory of device.
Directory tempDir = await getTemporaryDirectory();
// get temporary path from temporary directory.
String tempPath = tempDir.path;
// create a new file in temporary path with random file name.
File file = new File('$tempPath'+ (rng.nextInt(100)).toString() +'.svg');
// call http.get method and pass imageUrl into it to get response.
http.Response response = await http.get(imageUrl);
// write bodyBytes received in response to file.
await file.writeAsBytes(response.bodyBytes);
// now return the file which is created with random name in
// temporary directory and image bytes from response is written to // that file.
return file;
}