I am trying to put a watermark/Image on another image, we can zoom in, zoom out, drag and rotate the watermark image by fingertouch. I am using Open CV library to rotate the image as suggested in this post image rotation with opencv in android cuts off the edges of an image
It works fine until the rotation angle gets in between -75 to -105 and 75 to 105. In this range my image get cropped or it changes its position. I have tried several ways to get the right center point for the watermark image to put it in right position after rotating it but failed to do so.
Here is the code to rotate the image
// CALCULATE ROTATED WATERMARK IMAGE
private void CreateRotatedWaterMark()
{
// Means rotation took place
if (waterMarkAngle > 0 || waterMarkAngle < 0) {
// calculation for new width/height of rotated watermark image
newWidthHeight = boundingWaterMarkRect();
// remove when done testing
double pivotX = newWidthHeight[0] / 2; // 0 is width
double pivotY = newWidthHeight[1] / 2; // 1 is height
// rotating water image
org.opencv.core.Point center;
Size targetSize;
Mat targetMat;
// scalar is color/ RGBA , but alpha doesn't seem to work
Scalar colorScalar = new Scalar(255, 190, 190, 0);
double offsetX = (newWidthHeight[0] - scaledImage.width()) / 2;
double offsetY = (newWidthHeight[1] - scaledImage.height()) / 2;
// watermark's rotation lays somewhere in between 75' AND 105' OR
// -75' AND -105'
Log.e(TAG, "check => offsetX/offsetY Before => " + offsetX + " / "
+ offsetY);
if (offsetX < 0 || offsetY < 0) {
//this gets true when angle of rotation gets between -75 to -105 and 75 to 105
// change the offsets, now new newWidth < oldWidth AND newHeight
// > oldHeight (could be vice versa)
offsetX = (newWidthHeight[0] - scaledImage.height()) / 2;
offsetY = (newWidthHeight[1] - scaledImage.width()) / 2;
// Declaring new target size and target Mat, so rotated image is
// placed in new target Mat
targetSize = new Size(newWidthHeight[1], newWidthHeight[0]);
targetMat = new Mat(targetSize, scaledImage.type(), colorScalar);
// Getting the reference of center area from target Mat,
// below we're copying the actual image (scaledImage) to center
// position to target Mat
Mat waterSubmat = targetMat.submat((int) offsetX, (int) offsetX
+ scaledImage.height(), (int) offsetY, (int) offsetY
+ scaledImage.width());
scaledImage.copyTo(waterSubmat);
// Writing target image to sdcard, so we can know if its working
// properly, remove it when done with testing
Highgui.imwrite("mnt/sdcard/scaled90.png", targetMat);
Highgui.imwrite("mnt/sdcard/waterSubmat.png", waterSubmat);
Highgui.imwrite("mnt/sdcard/ScaledImage.png", scaledImage);
// targetSize is reverted again, so that target mat is pasted on
// canvas image
targetSize = new Size(newWidthHeight[0], newWidthHeight[1]);
pivotX = newWidthHeight[0] / 2;
pivotY = newWidthHeight[1] / 2;
Log.e(TAG, "check => pivotX/pivotY => " + pivotX + " / "
+ pivotY);
Log.e(TAG, "check => Angle => " + waterMarkAngle);
center = new org.opencv.core.Point(pivotX, pivotY);
} else {
center = new org.opencv.core.Point(pivotX, pivotY);
targetSize = new Size(newWidthHeight[0], newWidthHeight[1]);
targetMat = new Mat(targetSize, scaledImage.type(), colorScalar);
// Centralizing watermark
Mat waterSubmat = targetMat.submat((int) offsetY, (int) offsetY
+ scaledImage.height(), (int) offsetX, (int) offsetX
+ scaledImage.width());
scaledImage.copyTo(waterSubmat);
Highgui.imwrite("mnt/sdcard/scaled10.png", targetMat);
}
Mat rotImage = Imgproc.getRotationMatrix2D(center, waterMarkAngle,
1.0); // 1.0 means scale 100%
Highgui.imwrite("mnt/sdcard/Rotated90.png", rotImage);
// Mat waterSubmat1 = rotImage.submat(0, scaledImage.height(), 0,
// scaledImage.width());
Mat resultMat = new Mat();
// scalar for color, Imagproc.warAffine actually rotates the final
// watermark on canvas image
colorScalar = new Scalar(122, 22, 22);
Imgproc.warpAffine(targetMat, resultMat, rotImage, targetSize,
Imgproc.INTER_LINEAR, Imgproc.BORDER_CONSTANT, colorScalar);
Log.i(TAG, "check MATRIX = " + resultMat.toString());
Log.i(TAG, "check Result Mat " + resultMat.size().toString());
scaledImage = resultMat.clone();
Highgui.imwrite("mnt/sdcard/Result100.png", targetMat);
// Log.i(TAG, "check Result postion = "+ resultMat.r);
// WRITE SOME TEXT ON CANVAS IMAGE, its not rotated
Core.putText(scaledImage, "angle: " + waterMarkAngle,
new org.opencv.core.Point(0, scaledImage.height() / 2),
Core.FONT_HERSHEY_TRIPLEX, 2, new Scalar(23, 12, 450, 0.5),
2); // CV_BLUR_NO_SCALE
} else {
// CHANGE OPACITY OF WATERMARK IMAGE
// Core.multiply(scaledImage, new Scalar(1, 1, 1, 0.6),
// scaledImage);
// REMOVE THIS WHEN DONE TESTING
// Highgui.imwrite("mnt/sdcard/opacityWatermark.png",scaledImage);
}
}
private double[] boundingWaterMarkRect() {
// -----NEW CALCULATION------
// so we always get positive angle
double tempAngle = ((waterMarkAngle < 0 ? 360 - waterMarkAngle : waterMarkAngle) % 360);
double radians = Math.toRadians(tempAngle);
Log.i(TAG, "check => radian => "+ radians);
double sin = Math.abs(Math.sin(radians));
double cos = Math.abs(Math.cos(radians));
double newWidth = (double) (scaledImage.width() * cos + scaledImage.height() * sin);
double newHeight = (double) (scaledImage.width() * sin + scaledImage.height() * cos);
double[] wh = {newWidth, newHeight};
return wh;
}
Following are two images first one is right and the other is rotated wrong
Anyone have got solution for it?