I have a QrCode which i want to change its colours to white and blue...
I can do it using the following code:
val bitmap = qrgEncoder.encodeAsBitmap()
val width = bitmap.width
val height = bitmap.height
// All are 0, or black, by default
for (y in 0 until height) {
for (x in 0 until width) {
bitmap.getPixel(x, y).also {
if(it != -1)
bitmap.setPixel(x, y, ResourcesCompat.getColor(resources, R.color.defaultTextColor, null))
else
bitmap.setPixel(x, y, ResourcesCompat.getColor(resources, R.color.toolbarColor, null))
}
}
}
// Setting Bitmap to ImageView
qrImage.setImageBitmap(bitmap)
but this is too slow... so I am wondering what is the best approach to do the same thing and faster.
After trying different solutions, I realised the only way is to manipulate the pixels.
The following code is the optimum solution for now:
val pixelsArray = IntArray(mWidth * mHeight)
val newColor1 = getColor(context!!, R.color.color1)
val newColor2 = getColor(context!!, R.color.color2)
bitmap.getPixels(pixelsArray, 0, mWidth, 0, 0, mWidth, mHeight)
for (y in 0 until pixelsArray.size) {
if (pixelsArray[y] != -1)
pixelsArray[y] = newColor1
else
pixelsArray[y] = newColor2
}
note for accepted answer by msc87,
to save pixelsArray back to bitmap use:
bitmap.setPixels(pixelsArray,0,mWidth,0,0,mWidth,maskHeight)
you can also replace getColour to: (if needed)
Color.argb(255,0,177,64)
ect..
You can set a Drawable tint:
https://developer.android.com/reference/android/support/v4/graphics/drawable/DrawableCompat.html#setTint(android.graphics.drawable.Drawable,%20int)
val bitmap: Bitmap = ...
val bitmapDrawable = BitmapDrawable(resources, bitmap)
DrawableCompat.setTint(bitmapDrawable, Color.BLUE)
Related
I want to write a simple code - resize function without library. I must use getPixel and setPixel, result may be without normal quality. But I don't know how make it.
fun resuzeimage(bitmap:Bitmap,newWidth,newHeight){
for (j in 0 until bitmap.height) {
for (i in 0 until butmap.width) {
///code
}
}
}
Pleas, help me
fun resizeImage(yourBitmap: Bitmap, newWidth :Int, newHeight :Int):Bitmap
{
var resized = Bitmap.createScaledBitmap(yourBitmap!!, newWidth, newHeight, true)
return resized
}
You can change height and width return type as per your need.
I want to be able to get the exact image for analysis step as I get in preview.
I have preview use case:
val metrics = DisplayMetrics().also { binding.codeScannerView.display.getRealMetrics(it) }
val screenAspectRatio = Rational(metrics.widthPixels, metrics.heightPixels)
val previewConfig = PreviewConfig.Builder().apply {
setTargetAspectRatio(screenAspectRatio)
}.build()
And next to it I have analysis use case config:
val analyzerConfig = ImageAnalysisConfig.Builder().apply {
setTargetResolution(Size(metrics.heightPixels, metrics.widthPixels))
setTargetAspectRatio(screenAspectRatio)
val analyzerThread = HandlerThread(
"QrCodeReader").apply { start() }
setCallbackHandler(Handler(analyzerThread.looper))
setImageReaderMode(
ImageAnalysis.ImageReaderMode.ACQUIRE_LATEST_IMAGE)
}.build()
My preview is fullscreen so it's size is 1440x2560. But if I try to get dimensions from ImageProxy in analyzer, I get 1920x1050 which seems to have incorrect dimensions and switched width with height. Why is that and how can I force my analysis step to have same dimensions as full screen?
Intro:
implementation 'androidx.camera:camera-core:1.0.0-alpha10'
implementation 'androidx.camera:camera-camera2:1.0.0-alpha10'
implementation "androidx.camera:camera-lifecycle:1.0.0-alpha10"
implementation "androidx.camera:camera-view:1.0.0-alpha07"
implementation 'com.google.firebase:firebase-ml-vision:24.0.1'
implementation 'com.google.firebase:firebase-ml-vision-barcode-model:16.0.2'
I am solve this issue via the method FirebaseVisionImage.fromBitmap(bitmap)
where bitmap - manual cropped && rotated image according to preview configuration.
The steps are:
when you setup ImageAnalysis.Builder() && Preview.Builder()
obtain the on-screen rendered size for
androidx.camera.view.PreviewView element:
previewView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)
val previewSize = Size(previewView.width, previewView.height)
Then pass the size into your own ImageAnalysis.Analyzer
implementation (let's say it will be viewFinderSize variable, usage see below)
when override fun analyze(mediaImage: ImageProxy){ occurs, do the manual crop of received ImageProxy. I am use the snippet from another SO question about distorted YUV_420_888 image: https://stackoverflow.com/a/45926852/2118862
When you do the cropping, keep in mind that ImageAnalysis use case receive image aligned in vertical-middle basis within your preview use case. In other words, received image, after rotation will be vertically centred as if it will be inside your preview area (even if your preview area is smaller than the image passed into analysis). So, crop area should be calculated in both directions from the vertical center: up and down.
The vertical size of the crop (height) should be manually calculated on the horizontal size basis. This means, when you receive image into analysis, it has full horizontal size within your preview area (100% of width inside preview is equal 100% of width inside analysis). So, no hidden zones in horizontal dimension. This open the way to calculate the size for vertical cropping. I am done this with next code:
var bitmap = ... <- obtain the bitmap as suggested in the SO link above
val matrix = Matrix()
matrix.postRotate(90f)
bitmap = Bitmap.createBitmap(bitmap, 0, 0, image.width, image.height, matrix, true)
val cropHeight = if (bitmap.width < viewFinderSize!!.width) {
// if preview area larger than analysing image
val koeff = bitmap.width.toFloat() / viewFinderSize!!.width.toFloat()
viewFinderSize!!.height.toFloat() * koeff
} else {
// if preview area smaller than analysing image
val prc = 100 - (viewFinderSize!!.width.toFloat()/(bitmap.width.toFloat()/100f))
viewFinderSize!!.height + ((viewFinderSize!!.height.toFloat()/100f) * prc)
}
val cropTop = (bitmap.height/2)-((cropHeight)/2)
bitmap = Bitmap.createBitmap(bitmap, 0, cropTop.toInt(), bitmap.width, cropHeight.toInt())
The final value in bitmap variable - is the cropped image ready to pass into FirebaseVisionImage.fromBitmap(bitmap)
PS.
welcome to improve the suggested variant
May be I am late but here is the code working for me
Few times if the the cropTop comes as -ve value so whenever the negative value comes you should process image which comes from ImageProxy in other cases you can process cropped bitmap
val mediaImage = imageProxy.image ?: return
var bitmap = ImageUtils.convertYuv420888ImageToBitmap(mediaImage)
val rotationDegrees = imageProxy.imageInfo.rotationDegrees
val matrix = Matrix()
matrix.postRotate(rotationDegrees.toFloat())
bitmap =
Bitmap.createBitmap(bitmap, 0, 0, mediaImage.width, mediaImage.height, matrix, true)
val cropHeight = if (bitmap.width < previewView.width) {
// if preview area larger than analysing image
val koeff = bitmap.width.toFloat() / previewView.width.toFloat()
previewView.height.toFloat() * koeff
} else {
// if preview area smaller than analysing image
val prc = 100 - (previewView.width.toFloat() / (bitmap.width.toFloat() / 100f))
previewView.height + ((previewView.height.toFloat() / 100f) * prc)
}
val cropTop = (bitmap.height / 2) - ((cropHeight) / 2)
if (cropTop > 0) {
Bitmap.createBitmap(bitmap, 0, cropTop.toInt(), bitmap.width, cropHeight.toInt())
.also { process(it, imageProxy) }
} else {
imageProxy.image?.let { process(it, imageProxy) }
}
I am trying to load bitmap from ImageView to SKCanvasView.
The problem is that this image has CenterCrop set and image that was loaded to canvas is way too big. How to make it look exactly like in ImageView?
Code samples:
_skBitmap = ((BitmapDrawable)_frontView.ImageView.Drawable).Bitmap.ToSKBitmap();
And drawing:
private void _canvas_PaintSurface(object sender, SKPaintSurfaceEventArgs e)
{
var canvas = e.Surface.Canvas;
var scale = Resources.DisplayMetrics.Density;
canvas.Scale(scale);
if (_skBitmap != null)
{
canvas.DrawBitmap(_skBitmap, e.Info.Rect);
}
}
In case someone is interested (in my case image is always wider then screen):
private void _canvas_PaintSurface(object sender, SKPaintSurfaceEventArgs e)
{
var canvas = e.Surface.Canvas;
var scale = Resources.DisplayMetrics.Density;
canvas.Scale(scale);
if (_skBitmap != null)
{
var factor = scaledSize.Height / _skBitmap.Height;
var nw = _skBitmap.Width * factor;
var offset = (scaledSize.Width - nw) / 2;
var sr = new SKRect(offset, 0, nw + offset, scaledSize.Height);
canvas.DrawBitmap(_skBitmap, sr);
}
}
I am integrating a Tensorflow model in an Android app and I need to preprocess my image before feeding it to my model.
For that I need my image to :
crop my image to the right dimensions (no problem with this step) :
Bitmap bitmap_cropped = Bitmap.createScaledBitmap(bitmap, 224, 224,false);
get RGB chanels from 0-255 values to 0-1 range. So basically divide all pixels by 255. I tried the code below but I am not sure this does what I need :
bitmap_cropped.getPixels(imageBitmapPixels, 0, bitmap_cropped.getWidth(), 0, 0, bitmap_cropped.getWidth(), bitmap_cropped.getHeight());
for (int i = 0 ; i < imageBitmapPixels.length; i++) {
imageBitmapPixels[i] = imageBitmapPixels[i]/255;
}
But when I display the values of each pixels I get something like that
-12898260
-12963540
-12963540
-11254211
I guess the 3 chanels are mixed so I can't check if got what I wanted.. Is this the right way to do it ?
This can give you some idea of what you need to do
val rgbs = Array(bitmap.width * bitmap.height){
val x = it % bitmap.height
val y = it / bitmap.height
val pixel = bitmap.getPixel(x, y)
val red = (pixel and 0x00FF0000 shr 16) / 255f
val green = (pixel and 0x0000FF00 shr 8) / 255f
val blue = (pixel and 0x000000FF) / 255f
RGB(red, green, blue)
}
data class RGB(val r: Float, val g: Float, val b: Float)
Excuse my kotlin
disclamer 1: this code is not performant
disclamer 2: there is probably a lib which doing pretty much the same but faster
disclamer 3: the code above relies on your bitmap being ARGB_8888 format
I'm having problem with my file browser.
When it reached to any directory : Get folder list to list map, and use onBindCustomView for setting icon for each list items.
If that file format is image, it shows the image preview instead of showing image icon.
But the problem is, one or less than 10 image file is OK. But when the image file count is reached to over 50, it lags very hard.
I think this lag problem is caused by image preview. Because it didn't resize, so I add the code to resize image preview from any x any to 100x100.
But there is another problem.
bitmap.createBitmap(bitmap, 0, 0, 100, 100)
This cut image and make it small. This only resize the image. So the result is the small part of image.
Is there a method to resize the image and keep the image looks original?
You can use canvas:
In your view.
<script>
$('#files')
.bind('change', function(ev) {
message_loading("none");
ev.preventDefault();
ev.stopPropagation();
uploadFiles(this);
message_loading("display");
})
</script>
In your script
function uploadFiles(target) {
var content = target.files;
var img = reduceImgSize(content[0], content[0]["name"]);
}
function reduceImgSize(f, name){
var reader = new FileReader();
reader.onload = function (readerEvent) {
var image = new Image();
image.onload = function (imageEvent) {
var canvas = document.createElement('canvas'),
max_size = image.width/1.1,
width = image.width,
height = image.height;
if (width > height) {
if (width > max_size) {
height *= max_size / width;
width = max_size;
}
} else {
if (height > max_size) {
width *= max_size / height;
height = max_size;
}
}
canvas.width = width; // write your width
canvas.height = height; // write your height
canvas.getContext('2d').drawImage(image, 0, 0, width, height);
var dataUrl = canvas.toDataURL('image/jpeg');
var resizedImage = dataURLToBlob(dataUrl);
var imageFile = new File([resizedImage], name, {type : "image/jpeg"});
return imageFile;
}
image.src = readerEvent.target.result;
}
reader.readAsDataURL(f);
}
I hope it helps