with opencv i want crop top image portion and written this code.
// crop image
Integer halfWidth = width / 2;
Integer HalfHeight = height / 2;
Integer startX = halfWidth - (halfWidth / 2);
Mat mRgba = new Mat(HalfHeight, halfWidth, CvType.CV_8UC1);
Rect roi = new Rect(0, HalfHeight, width, height);
At result i got this result and my program shutdown.
Mat [ 360*480*CV_8UC1, isCont=true, isSubmat=false, nativeObj=0x5c54da18, dataAddr=0x60aa8010 ]
1549064728
{0, 360, 960x720}
My old object higher than first. How i can fix them?
From the code you provide, I can guess that your ROI should be:
Rect roi = new Rect(0, HalfHeight, width, height-HalfHeight);
My full code
protected void calculate(int width, int height, byte[] data)
{
Mat mYuv = new Mat(height + height / 2, width, CvType.CV_8UC1);
Mat thresholdImage = new Mat(height + height / 2, width, CvType.CV_8UC1);
mYuv.put(0, 0, data);
// crop image
Integer halfWidth = width / 2;
Integer HalfHeight = height / 2;
Integer startX = halfWidth - (halfWidth / 2);
Mat mRgba = new Mat(HalfHeight, halfWidth, CvType.CV_8UC1);
Rect roi = new Rect(0, HalfHeight, width, height-HalfHeight);
mRgba = new Mat(mRgba, roi);
Imgproc.cvtColor(mYuv, mRgba, Imgproc.COLOR_YUV420p2BGR, 4);
//convert to grayscale
Imgproc.cvtColor(mRgba, thresholdImage, Imgproc.COLOR_mRGBA2RGBA, 4);
// Perform a Gaussian blur (convolving in 5x5 Gaussian) & detect edges
//Imgproc.GaussianBlur(mRgba, mRgba, new Size(5,5), 2.2, 2);
Imgproc.Canny(mRgba, thresholdImage, VActivity.CANNY_MIN_TRESHOLD, VActivity.CANNY_MAX_THRESHOLD);
Mat lines = new Mat();
double rho = 0.15;
double theta = Math.PI/180;
int threshold = 50;
//do Hough transform to find lanes
Imgproc.HoughLinesP(thresholdImage, lines, rho, theta, threshold, VActivity.HOUGH_MIN_LINE_LENGTH, VActivity.HOUGH_MAX_LINE_GAP);
for (int x = 0; x < lines.cols() && x < 5; x++)
{
double[] vec = lines.get(0, x);
double x1 = vec[0],
y1 = vec[1],
x2 = vec[2],
y2 = vec[3];
Point start = new Point(x1, y1);
Point end = new Point(x2, y2);
Core.line(mRgba, start, end, new Scalar(255, 0, 0), 3);
}
if (bitmap == null)
bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Utils.matToBitmap(mRgba, bitmap);
drawThread.setBitmap(bitmap);
}
And got same error. Maybe in this i need send another params or just clone to mRgba
Mat mRgba = new Mat(HalfHeight, halfWidth, CvType.CV_8UC1);
Rect roi = new Rect(0, HalfHeight, width, height-HalfHeight);
mRgba = new Mat(mRgba, roi);
Related
My mRgba object has dimensions 0X0 so it doesn't return any lines on the picture
at all.I guess it is empty. What is the problem in the code? Is there a way to show lines just on
the black background?
Here is the code
mat = new Mat();
edges = new Mat();
Size kernel = new Size(5, 5);
Mat gauss = new Mat();
Mat mRgba = new Mat(612,816, CvType.CV_8UC1);
Mat lines = new Mat(612,816, CvType.CV_8UC1);
binary_image = new Mat();
Utils.bitmapToMat(bitmap, mat);
Imgproc.GaussianBlur(mat, gauss, kernel, 10000, 10000);
Imgproc.Canny(gauss, edges, 50, 90);
Imgproc.threshold(edges, binary_image, 0, 255, Imgproc.THRESH_BINARY_INV);
int threshold = 50;
int minLineSize = 20;
int lineGap = 20;
Imgproc.HoughLinesP(binary_image, lines, 1, Math.PI / 180,threshold,minLineSize,lineGap);
for (int x = 0; x < lines.cols(); x++) {
double[] vec = lines.get(0, x);
double x1 = vec[0],
y1 = vec[1],
x2 = vec[2],
y2 = vec[3];
Point start = new Point(x1, y1);
Point end = new Point(x2, y2);
Core.line(mRgba, start, end, new Scalar(255, 0, 0), 3);
}
Bitmap bmp = Bitmap.createBitmap(mRgba.cols(), mRgba.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(mRgba, bmp);
bitmap=bmp;
EDIT: The problem has been solved by removing GaussianBlur and threshold methods
mat = new Mat();
edges = new Mat();
Mat mRgba = new Mat(612,816, CvType.CV_8UC1);
Mat lines = new Mat();
Utils.bitmapToMat(bitmap, mat);
Imgproc.Canny(mat, edges, 50, 90);
int threshold = 50;
int minLineSize = 20;
int lineGap = 20;
Imgproc.HoughLinesP(edges, lines, 1, Math.PI / 180,threshold,minLineSize,lineGap);
for (int x = 0; x < lines.cols(); x++) {
double[] vec = lines.get(0, x);
double x1 = vec[0],
y1 = vec[1],
x2 = vec[2],
y2 = vec[3];
Point start = new Point(x1, y1);
Point end = new Point(x2, y2);
Core.line(mRgba, start, end, new Scalar(255, 0, 0), 3);
}
Bitmap bmp = Bitmap.createBitmap(mRgba.cols(), mRgba.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(mRgba, bmp);
bitmap=bmp;
You are not specifying a size for mRgba when you are creating it, it should has the same size with the image that you are trying to find lines.
You should check lines object, to see if you are able to find lines or
not. You can understand it by checking mRgba.
This doesn't seem to be the whole code, there is no image loading here. It might be better for you to share whole code and an example image as well.
When calling the following method:
Bitmap localBitmap = Bitmap.createScaledBitmap(paramBitmap, 360, (int)(360.0D / (paramBitmap.getWidth() / paramBitmap.getHeight())), false);
I get the exception trace as:
java.lang.IllegalArgumentException: bitmap size exceeds 32 bits
I printed the size of incoming bitmap using statements:
System.out.println("paramBitmap.getWidth() "+ paramBitmap.getWidth());
System.out.println("paramBitmap.getHeight() "+ paramBitmap.getHeight());
and it is 480x960
How to debug this problem and solve it.
i know its late but it might help somebody,I faced the same problem when i tried to draw a border for bitmap and rotate it to certain angle, it always crashed in xiaomi mi mobile, i solved it by scaling the bitmap as per the need,
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
Bitmap bmp = BitmapFactory.decodeFile(path, options);
final int BORDER_WIDTH = 10;
final int BORDER_COLOR = Color.YELLOW;
Bitmap res = Bitmap.createBitmap(bmp.getWidth() + 2 * BORDER_WIDTH,bmp.getHeight() + 2 * BORDER_WIDTH,bmp.getConfig());
Canvas c = new Canvas(res);
Paint p = new Paint();
p.setColor(BORDER_COLOR);
c.drawRect(0, 0, res.getWidth(), res.getHeight(), p);
p = new Paint(Paint.FILTER_BITMAP_FLAG);
c.drawBitmap(bmp, BORDER_WIDTH, BORDER_WIDTH, p);
float viewWidth = (float) res.getWidth();
float viewHeight = `enter code here`(float) res.getHeight();
float ratiowidth = vi`enter code here`ewWidth / (float) res.getWidth();
float ratioheight = viewHeight / (float) res.getHeight();
Matrix mat = new Matrix();
mat.postScale(ratiowidth, ratioheight);
mat.postRotate(45);
Bitmap bMapRotate = Bitmap.createBitmap(res, 0,0,res.getWidth(),res.getHeight(), mat, true);
I would like to draw the right part of an image, but the result is alwas a stretched image of the entire bitmap, or a stretched part of the center of the bitmap. What am I doing wrong here?
int width;
int percentToDraw;
Random rand = new Random();
percentToDraw = rand.nextInt(100);
width = bmp.getWidth() * (100 - percentToDraw) / 100;
src = new Rect();
src.top = 0;
src.bottom = bmp.getHeight();
src.right = bmp.getWidth();
src.left = src.right - width;
dst = new Rect;
dst.top = getHeight() / 2 - bmp.getHeight() / 2;
dst.bottom = dst.top + (src.bottom - src.height);
dst.right = getWidth() / 2 + bmp.getWidth() / 2;
dst.left = dst.right - width;
canvas.drawBitmap(bmp, src, dst, paint);
I have been fiddling and googling about this for two days now, widthout finding anything close to a solution :-(
In case anyone else stumbles over this, I have been unable to make it work "correctly" but I've found a working solution using clipRect:
int width;
width = (int) Math.floor(bmp.getWidth() * percentToDraw / 100.0);
src = new Rect();
src.top = 0;
src.bottom = bmp.getHeight();
src.left = 0;
src.right = bmp.getWidth();
dst = new Rect();
dst.top = getHeight() / 2 - bmp.getHeight() / 2;
dst.bottom = dst.top + (src.bottom - src.top);
dst.left = getWidth() / 2 - bmp.getWidth() / 2;
dst.right = dst.left + (src.right - src.left);
canvas.clipRect(dst.right - width, 0, getWidth(), getHeight(), Region.Op.REPLACE);
canvas.drawBitmap(bmp, src, dst, paint);
canvas.clipRect(0, 0, getWidth(), getHeight(), Region.Op.REPLACE);
I have bitmaps which are squares or rectangles. I take the shortest side and do something like this:
int value = 0;
if (bitmap.getHeight() <= bitmap.getWidth()) {
value = bitmap.getHeight();
} else {
value = bitmap.getWidth();
}
Bitmap finalBitmap = null;
finalBitmap = Bitmap.createBitmap(bitmap, 0, 0, value, value);
Then I scale it to a 144 x 144 Bitmap using this:
Bitmap lastBitmap = null;
lastBitmap = Bitmap.createScaledBitmap(finalBitmap, 144, 144, true);
Problem is that it crops the top left corner of the original bitmap, Anyone has the code to crop the center of the bitmap?
This can be achieved with: Bitmap.createBitmap(source, x, y, width, height)
if (srcBmp.getWidth() >= srcBmp.getHeight()){
dstBmp = Bitmap.createBitmap(
srcBmp,
srcBmp.getWidth()/2 - srcBmp.getHeight()/2,
0,
srcBmp.getHeight(),
srcBmp.getHeight()
);
}else{
dstBmp = Bitmap.createBitmap(
srcBmp,
0,
srcBmp.getHeight()/2 - srcBmp.getWidth()/2,
srcBmp.getWidth(),
srcBmp.getWidth()
);
}
While most of the above answers provide a way to do this, there is already a built-in way to accomplish this and it's 1 line of code (ThumbnailUtils.extractThumbnail())
int dimension = getSquareCropDimensionForBitmap(bitmap);
bitmap = ThumbnailUtils.extractThumbnail(bitmap, dimension, dimension);
...
//I added this method because people keep asking how
//to calculate the dimensions of the bitmap...see comments below
public int getSquareCropDimensionForBitmap(Bitmap bitmap)
{
//use the smallest dimension of the image to crop to
return Math.min(bitmap.getWidth(), bitmap.getHeight());
}
If you want the bitmap object to be recycled, you can pass options that make it so:
bitmap = ThumbnailUtils.extractThumbnail(bitmap, dimension, dimension, ThumbnailUtils.OPTIONS_RECYCLE_INPUT);
From: ThumbnailUtils Documentation
public static Bitmap extractThumbnail (Bitmap source, int width, int
height)
Added in API level 8 Creates a centered bitmap of the desired size.
Parameters source original bitmap source width targeted width
height targeted height
I was getting out of memory errors sometimes when using the accepted answer, and using ThumbnailUtils resolved those issues for me. Plus, this is much cleaner and more reusable.
Have you considered doing this from the layout.xml ? You could set for your ImageView the ScaleType to android:scaleType="centerCrop" and set the dimensions of the image in the ImageView inside the layout.xml.
You can used following code that can solve your problem.
Matrix matrix = new Matrix();
matrix.postScale(0.5f, 0.5f);
Bitmap croppedBitmap = Bitmap.createBitmap(bitmapOriginal, 100, 100,100, 100, matrix, true);
Above method do postScalling of image before cropping, so you can get best result with cropped image without getting OOM error.
For more detail you can refer this blog
Here a more complete snippet that crops out the center of an [bitmap] of arbitrary dimensions and scales the result to your desired [IMAGE_SIZE]. So you will always get a [croppedBitmap] scaled square of the image center with a fixed size. ideal for thumbnailing and such.
Its a more complete combination of the other solutions.
final int IMAGE_SIZE = 255;
boolean landscape = bitmap.getWidth() > bitmap.getHeight();
float scale_factor;
if (landscape) scale_factor = (float)IMAGE_SIZE / bitmap.getHeight();
else scale_factor = (float)IMAGE_SIZE / bitmap.getWidth();
Matrix matrix = new Matrix();
matrix.postScale(scale_factor, scale_factor);
Bitmap croppedBitmap;
if (landscape){
int start = (tempBitmap.getWidth() - tempBitmap.getHeight()) / 2;
croppedBitmap = Bitmap.createBitmap(tempBitmap, start, 0, tempBitmap.getHeight(), tempBitmap.getHeight(), matrix, true);
} else {
int start = (tempBitmap.getHeight() - tempBitmap.getWidth()) / 2;
croppedBitmap = Bitmap.createBitmap(tempBitmap, 0, start, tempBitmap.getWidth(), tempBitmap.getWidth(), matrix, true);
}
Probably the easiest solution so far:
public static Bitmap cropCenter(Bitmap bmp) {
int dimension = Math.min(bmp.getWidth(), bmp.getHeight());
return ThumbnailUtils.extractThumbnail(bmp, dimension, dimension);
}
imports:
import android.media.ThumbnailUtils;
import java.lang.Math;
import android.graphics.Bitmap;
To correct #willsteel solution:
if (landscape){
int start = (tempBitmap.getWidth() - tempBitmap.getHeight()) / 2;
croppedBitmap = Bitmap.createBitmap(tempBitmap, start, 0, tempBitmap.getHeight(), tempBitmap.getHeight(), matrix, true);
} else {
int start = (tempBitmap.getHeight() - tempBitmap.getWidth()) / 2;
croppedBitmap = Bitmap.createBitmap(tempBitmap, 0, start, tempBitmap.getWidth(), tempBitmap.getWidth(), matrix, true);
}
public Bitmap getResizedBitmap(Bitmap bm) {
int width = bm.getWidth();
int height = bm.getHeight();
int narrowSize = Math.min(width, height);
int differ = (int)Math.abs((bm.getHeight() - bm.getWidth())/2.0f);
width = (width == narrowSize) ? 0 : differ;
height = (width == 0) ? differ : 0;
Bitmap resizedBitmap = Bitmap.createBitmap(bm, width, height, narrowSize, narrowSize);
bm.recycle();
return resizedBitmap;
}
public static Bitmap resizeAndCropCenter(Bitmap bitmap, int size, boolean recycle) {
int w = bitmap.getWidth();
int h = bitmap.getHeight();
if (w == size && h == size) return bitmap;
// scale the image so that the shorter side equals to the target;
// the longer side will be center-cropped.
float scale = (float) size / Math.min(w, h);
Bitmap target = Bitmap.createBitmap(size, size, getConfig(bitmap));
int width = Math.round(scale * bitmap.getWidth());
int height = Math.round(scale * bitmap.getHeight());
Canvas canvas = new Canvas(target);
canvas.translate((size - width) / 2f, (size - height) / 2f);
canvas.scale(scale, scale);
Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG);
canvas.drawBitmap(bitmap, 0, 0, paint);
if (recycle) bitmap.recycle();
return target;
}
private static Bitmap.Config getConfig(Bitmap bitmap) {
Bitmap.Config config = bitmap.getConfig();
if (config == null) {
config = Bitmap.Config.ARGB_8888;
}
return config;
}
val sourceWidth = source.width
val sourceHeight = source.height
val xScale = newWidth.toFloat() / sourceWidth
val yScale = newHeight.toFloat() / sourceHeight
val scale = xScale.coerceAtLeast(yScale)
val scaledWidth = scale * sourceWidth
val scaledHeight = scale * sourceHeight
val left = (newWidth - scaledWidth) / 2
val top = (newHeight - scaledHeight) / 2
val targetRect = RectF(
left, top, left + scaledWidth, top
+ scaledHeight
)
val dest = Bitmap.createBitmap(
newWidth, newHeight,
source.config
)
val mutableDest = dest.copy(source.config, true)
val canvas = Canvas(mutableDest)
canvas.drawBitmap(source, null, targetRect, null)
binding.imgView.setImageBitmap(mutableDest)
I've been trying this for some time, I would like to create a wallpaper from a Bitmap. Let's say the desired wallpaper size is 320x480, and the source image size is 2048x2048.
I'm not sure whether crop-to-fit is the right term, but what I would like to achieve is to get most part of the picture that has the equal ratio as the desired wallpaper size (320x480).
So in this case, I would like to get 2048x1365 or (1365.333... to be exact) from the source Bitmap, and scale it down to 320x480.
The technique that I have tried is:
1) Crop the Bitmap into 2048x1365 first
bm = Bitmap.createBitmap(bm, xOffset, yOffset, 2048, 1365);
2) Scale it down to 320x480
bm = Bitmap.createScaledBitmap(bm, 320, 480, false);
which produced OutOfMemory error.
Is there any way to achieve this?
Regards,
dezull
Thanks to open source, I found the answer from Android Gallery source code here at line 230 :-D
croppedImage = Bitmap.createBitmap(mOutputX, mOutputY, Bitmap.Config.RGB_565);
Canvas canvas = new Canvas(croppedImage);
Rect srcRect = mCrop.getCropRect();
Rect dstRect = new Rect(0, 0, mOutputX, mOutputY);
int dx = (srcRect.width() - dstRect.width()) / 2;
int dy = (srcRect.height() - dstRect.height()) / 2;
// If the srcRect is too big, use the center part of it.
srcRect.inset(Math.max(0, dx), Math.max(0, dy));
// If the dstRect is too big, use the center part of it.
dstRect.inset(Math.max(0, -dx), Math.max(0, -dy));
// Draw the cropped bitmap in the center
canvas.drawBitmap(mBitmap, srcRect, dstRect, null);
I know this is an incredibly late reply, but something like this maybe:
public static Bitmap scaleCropToFit(Bitmap original, int targetWidth, int targetHeight){
//Need to scale the image, keeping the aspect ration first
int width = original.getWidth();
int height = original.getHeight();
float widthScale = (float) targetWidth / (float) width;
float heightScale = (float) targetHeight / (float) height;
float scaledWidth;
float scaledHeight;
int startY = 0;
int startX = 0;
if (widthScale > heightScale) {
scaledWidth = targetWidth;
scaledHeight = height * widthScale;
//crop height by...
startY = (int) ((scaledHeight - targetHeight) / 2);
} else {
scaledHeight = targetHeight;
scaledWidth = width * heightScale;
//crop width by..
startX = (int) ((scaledWidth - targetWidth) / 2);
}
Bitmap scaledBitmap = Bitmap.createScaledBitmap(original, (int) scaledWidth, (int) scaledHeight, true);
Bitmap resizedBitmap = Bitmap.createBitmap(scaledBitmap, startX, startY, targetWidth, targetHeight);
return resizedBitmap;
}
here is an answer that gets you most of the way there:
How to crop an image in android?