i create Android apps, that need skew angle detection. When image input in a slanting position after the image is processed using that functions, it will turn into a perpendicular position.
So, i use Leptonica (tess-two library) to achieve that, i used FindSkew() function here is my piece source code :
// get bitmap picture
BitmapFactory.Options PictureOptions = new BitmapFactory.Options();
PengaturanGambarCapture.inSampleSize = 2;
Image = BitmapFactory.decodeByteArray(data, 0, data.length, PictureOptions);
// get skew angle value
float SkewValue = Skew.findSkew(ReadFile.readBitmap(Image));
// rotate bitmap using matrix
int w = Image.getWidth();
int h = Image.getHeight();
Matrix MatrixSkew = new Matrix();
MatrixSkew.postRotate(SkewValue);
Bitmap BitmapSkew = Bitmap.createBitmap(Image, 0, 0, w, h, MatrixSkew, true);
// set BitmapSkew to imageview
OutputImage.setImageBitmap(BitmapSkew);
But when it run does not happen, ... the picture still in a tilted position. What's my mistake ??? Would you help me to fix it or you have other ways to rotate tilted images automatically. Thank you
Related
I am trying to further process a Camera2 image. Because the cameras in devices have different rotations and flipped based on back and front camera, I use transforms to properly rotate it.
transformationMatrix is that matrix for the front camera that has 270 rotation.
Then from that transformed camera image, I want to copy a scrolling window to another bitmap. I want to retain that bitmap/state and draw a line before drawing finalBitmapWithScanner on the phone screen.
Is there a way to do this more efficiently and fast? The second line takes 200ms to complete which is the main issue here.
Canvas canvas = new Canvas(tempBitmap);
canvas.drawBitmap(cameraBitmap, transformationMatrix, paint); // <= 200ms
Rect src = new Rect((int) lastXPos, 0, (int) mXPos, mViewHeight);
Canvas canvas2 = new Canvas(finalBitmap);
canvas2.drawBitmap(tempBitmap, src, src, paint);
Canvas canvas3 = new Canvas(finalBitmapWithScanner);
canvas3.drawBitmap(finalBitmap, 0, 0, paint);
canvas3.drawLine(mXPos, 0, mXPos, mViewHeight/2, scrollerPaint);
transformationMatrix.reset();
transformationMatrix.setRotate(270, imageHeight, 0);
transformationMatrix.postTranslate(-imageHeight, 0);
transformationMatrix.postScale(scaleFactor, scaleFactor);
transformationMatrix.postScale(-1f, 1f, mViewWidth / 2f, mViewHeight / 2f);
There are bunch of ways you can try to achieve fast rendering:
You can pass parameters "paint" an null.
also you can use function CreateScaledBitmap and notice you have to set scale and size before rendering as see in below:
As you can see in documentation enter link description here; you have to resize and rescale your bitmap before rendering so you can use code below for your BitmapFactory.Options :
mBitmapOptions.inScaled = true;
mBitmapOptions.inDensity = srcWidth;
mBitmapOptions.inTargetDensity = dstWidth;
// will load & resize the image to be 1/inSampleSize dimensions
mCurrentBitmap = BitmapFactory.decodeResources(getResources(),
mImageIDs, mBitmapOptions);
use canvas.restore() after draw func.
public void Rotate(View v)
{
ImageView img = (ImageView)findViewById(R.id.imageView1);
Bitmap bmp = BitmapFactory.decodeResource(getResources(),arr[current]);
// Getting width & height of the given image.
int w = bmp.getWidth();
int h = bmp.getHeight();
// Setting pre rotate to 90
Matrix mtx = new Matrix();
mtx.preRotate(90);
// Rotating Bitmap
Bitmap rotatedBMP = Bitmap.createBitmap(bmp, 0, 0, w, h, mtx, true);
BitmapDrawable bmd = new BitmapDrawable(rotatedBMP);
img.setImageBitmap(rotatedBMP);
}
when i select rotate option in menu it only rotates first time when i again select it, image wont rotate. any soln to it
actually, it does rotate your Bitmap each time for 90 degrees. Problem is you always get the same(not rotated) bitmap from the resources, not already rotated from your ImageView.
Instead of:
BitmapFactory.decodeResource(getResources(),arr[current]);
Try with this:
Bitmap bmp = ((BitmapDrawable)img.getDrawable()).getBitmap();
This solution is also better because you don't decode bitmap from resources each time.
i just used simple Math.
public void Rotate_r(View v)
{
rcount++;
if(rdgr==360) rdgr=90;
else rdgr=rdgr+90;
if(rcount==1){
ldgr=rdgr;
rcount--;
}
ImageView img = (ImageView)findViewById(iv);
Bitmap bmp =BitmapFactory.decodeResource(getResources(),arr[current]);
// Getting width & height of the given image.
int w = bmp.getWidth();
int h = bmp.getHeight();
// Setting pre rotate to 90
Matrix mtx = new Matrix();
mtx.preRotate(rdgr);
// Rotating Bitmap
Bitmap rotatedBMP = Bitmap.createBitmap(bmp, 0, 0, w, h, mtx, true);
#SuppressWarnings("deprecation")
BitmapDrawable bmd = new BitmapDrawable(rotatedBMP);
img.setImageBitmap(rotatedBMP);
}
i used a counter rcount which simply increments if image is rotated right and decrements if it is rotated left. also a variable rdgr is initialized to 90 as rdgr=90 and when rcount is incremented it adds 90 more to rdgr and plots the image.
My application has a "photobooth" feature which will allow the user to take a picture with the camera and at the same time show an overlay image on top of the camera view. After the picture is taken, i need to save what the user saw while taking the picture to the filesystem.
I have experienced 1 big problem while developing a solution to this: capturing an image with the compatible dimensions in which i can attach an overlay image to resulting in what the user saw while taking the picture.
It seems i cannot capture an image from the camera with defined dimensions(i have to basically pick from a list of them). Some phones only can produce certain dimensions.
Since i cannot choose the size of the captured image, it seems as though i will be required to include many different sizes of the overlay image, and attach the best match to the captured image. I can't just slap any old overlay on top of the camera image and make it look right.
Questions:
Am i over-complicating this "camera image + overlay image creation" process?
What suggestions do you have in completing this task without the need of including several different sizes overlay images?
Edit:
Here is my solution(brief). Please realize this is not a perfect and maybe not most efficient way to do this, but it works. Some things may be unnecessary/redundant but whatever!
Notes:
this doesn't work too great on tablet devices.
the overlay image needs to be rotated to be in landscape mode(even though you will be taking the image holding the phone in portrait)
overlay size is 480x320
you need to force the activity to landscape mode while taking the picture(now the overlay looks like its portrait!)
i add the overlay image view using addContentView(overlayImageView, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
...
final Camera.PictureCallback jpegCallback = new Camera.PictureCallback() {
#Override
public void onPictureTaken(byte[] data, Camera camera) {
BitmapFactory.Options options = new BitmapFactory.Options();
Bitmap mutableBitmap = null;
try {
//for a PORTRAIT overlay and taking the image holding the phone in PORTRAIT mode
mutableBitmap = BitmapFactory.decodeByteArray(data, 0, data.length, options).copy(Bitmap.Config.RGB_565, true);
Matrix matrix = new Matrix();
int width = mutableBitmap.getWidth();
int height = mutableBitmap.getHeight();
int newWidth = overlayImage.getDrawable().getBounds().width();
int newHeight = overlayImage.getDrawable().getBounds().height();
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
matrix.postScale(scaleWidth, scaleHeight);
matrix.postRotate(90);
Bitmap resizedBitmap = Bitmap.createBitmap(mutableBitmap, 0, 0, mutableBitmap.getWidth(), mutableBitmap.getHeight(), matrix, true);
finalBitmap = resizedBitmap.copy(Bitmap.Config.RGB_565, true);
Canvas canvas = new Canvas(finalBitmap);
Bitmap overlayBitmap = BitmapFactory.decodeResource(getResources(), overlay);
matrix = new Matrix();
matrix.postRotate(90);
Bitmap resizedOverlay = Bitmap.createBitmap(overlayBitmap, 0, 0, overlayBitmap.getWidth(), overlayBitmap.getHeight(), matrix, true);
canvas.drawBitmap(resizedOverlay, 0, 0, new Paint());
canvas.scale(50, 0);
canvas.save();
//finalBitmap is the image with the overlay on it
}
catch(OutOfMemoryError e) {
//fail
}
}
}
I think this is a question of how you manipulate your overlays. You can crop it according to the captured image size and resize it to fit, preserving its ratio. You can place the overlay, by comparing its ratio to the backround ratio, to its optimal position.
I would keep overlays big enough, with a wide border (bleed), to easily size them to an image using filters to draw it with good qaulity. I guess overlays are something which you would design and have transparent parts, like an image of a clown without a face so the user can snap somebody elses face into it?
I'm trying to rotate an image around the center. This works generally using RotateAnimation, but I want to have it a bit faster. I'm now using the SurfaceView pattern with a separate drawing thread.
This is code, which draws the bitmap correctly (depending on the outer "heading")
heading = angle in degrees,
bitmap = the bitmap,
w = width of the bitmap,
h = height of the bitmap.
Matrix m = new Matrix();
m.preRotate(heading, w/2, h/2);
m.setTranslate(50,50);
canvas.drawBitmap(bitmap, m, null);
Drawback: The image is a circle and the code above produces visible aliasing effects...
The code below is also rotating the image, but while rotating (say from 0 to 45 degrees clockwise) the center of the new image moves bottom/right. I suppose, the eccentric effect is due to the enlarged width/height of the new image ?? However, this code doesn't produce aliasing, if filter=true is set. Is there a way to use code #1 but have sort of anti-aliasing or use code #2 but getting rid of the center movement?
Matrix m = new Matrix();
m.preRotate(heading, w/2, h/2);
m.setTranslate(50,50);
Bitmap rbmp = Bitmap.createBitmap(bitmap, 0, 0, w, h, m, true);
canvas.drawBitmap(rbmp, 50, 50, null);
UPDATE: As result of the discussion in this thread the correct version of code #2 (anti-aliasing and correct rotation) would look like this (offset of 50,50 omitted):
Matrix m = new Matrix();
m.setRotate(heading, w/2, h/2);
Bitmap rbpm = Bitmap.createBitmap(bitmap, 0, 0, w, h, m, true);
canvas.drawBitmap(rbpm, (w - rbpm.getWidth())/2, (h - rbpm.getHeight())/2, null);
Thanks.
Find the center of the original image and for the new image and center using that:
Matrix minMatrix = new Matrix();
//height and width are set earlier.
Bitmap minBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas minCanvas = new Canvas(minBitmap);
int minwidth = bitmapMin.getWidth();
int minheight = bitmapMin.getHeight();
int centrex = minwidth/2;
int centrey = minheight/2;
minMatrix.setRotate(mindegrees, centrex, centrey);
Bitmap newmin = Bitmap.createBitmap(minBitmap, 0, 0, (int) minwidth, (int) minheight, minMatrix, true);
minCanvas.drawBitmap(newmin, (centrex - newmin.getWidth()/2), (centrey - newmin.getHeight()/2), null);
minCanvas.setBitmap(minBitmap);
I'm trying to rotate an image at a fixed point, but the image is rotating at its top left position. I've tried rotateAnimation and it works fine, but the problem is when I rotate my image again it starts rotating from the original position.
Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.arw2);
int w = bmp.getWidth();
int h = bmp.getHeight();
float px = 160,py = 215;
Matrix mtx = new Matrix();
mtx.setRotate(rAngle, px, py);
Bitmap rotatedBMP = Bitmap.createBitmap(bmp, 0, 0, w, h, mtx, true);
BitmapDrawable bmd = new BitmapDrawable(rotatedBMP);
myImageView.setImageDrawable(bmd);
What am I doing wrong?
If I understand your question correctly, you want to be able to rotate an image once, and then a second time, from where it left off.
You could do this by rotating the image by 30 degrees once, and then rotating that image again by 30 degrees (60 degrees in total), but this would result in a loss in quality and the centre point would be incorrect.
A better solution would be simply to change the value of rAngle that you use each time, and always create the rotated image based on the original un-rotated source image. So rather than rotating by (e.g.) 30 degrees each time, you rotate by 30 degrees or 60 degrees or 90 degrees etc.
If you wanted an image to rotate 30 degrees each time a button was clicked, you'd store the number of clicks in a variable such as buttonClicks, and then set rAngle = buttonClicks * 30 and perform the rotation.