在安卓中使用OpenCV进行图像旋转会裁剪掉图像的边缘

8
下面的代码可以成功地旋转图像,但它会切掉图像的角落并且旋转方向错误!这是一个可能重复的问题,请参考: 使用cv::warpAffine旋转cv::Mat时如何偏移目标图像
Mat cvImage = Highgui.imread("mnt/sdcard/canvasgrid.png");
int degrees = 20;
Point center = new Point(cvImage.cols()/2, cvImage.rows()/2);
Mat rotImage = Imgproc.getRotationMatrix2D(center, degrees, 1.0);
Mat dummy = cvWaterImage;
Imgproc.warpAffine(cvImage, dummy, rotImage, cvImage.size());
rotatedImage = dummy;

Highgui.imwrite("mnt/sdcard/imageRotate.png",rotatedImage);

原始图片

旋转图片

另外,旋转后的背景是黑色的,但我希望它是透明的。

我做错了什么吗? 谢谢

编辑已经解决

首先获得旋转图片的新宽度/高度

double radians = Math.toRadians(rotationAngle);
double sin = Math.abs(Math.sin(radians));
double cos = Math.abs(Math.cos(radians));

int newWidth = (int) (scaledImage.width() * cos + scaledImage.height() * sin);
int newHeight = (int) (scaledImage.width() * sin + scaledImage.height() * cos);

int[] newWidthHeight = {newWidth, newHeight};

// 创建新的尺寸框(newWidth/newHeight)

int pivotX = newWidthHeight[0]/2; 
int pivotY = newWidthHeight[1]/2;

// 旋转的水印图片

org.opencv.core.Point center = new org.opencv.core.Point(pivotX, pivotY);
Size targetSize = new Size(newWidthHeight[0], newWidthHeight[1]);

//现在创建另一个矩阵,以便我们可以用它进行映射

Mat targetMat = new Mat(targetSize, scaledImage.type());

int offsetX = (newWidthHeight[0] - scaledImage.width()) / 2;
int offsetY = (newWidthHeight[1] - scaledImage.height()) / 2;

// 居中水印

Mat waterSubmat = targetMat.submat(offsetY, offsetY + scaledImage.height(), offsetX,     offsetX + scaledImage.width());
scaledImage.copyTo(waterSubmat);

Mat rotImage = Imgproc.getRotationMatrix2D(center, waterMarkAngle, 1.0);
Mat resultMat = new Mat(); // CUBIC
Imgproc.warpAffine(targetMat, resultMat, rotImage, targetSize, Imgproc.INTER_LINEAR,    Imgproc.BORDER_CONSTANT, colorScalar);

//你的结果矩阵应该像这样 未裁剪的图像 //顺便说一下,提供的链接和这个解决方案之间有很大的区别


3
如果你不改变画布的物理尺寸且保持图像大小不变,那么边缘被剪裁的情况是明显的。你可以A)提供一个更大的画布或B)改变旋转矩阵,使其在旋转图像的同时缩小图像。 - Nippey
1
谢谢您的回答,有没有办法旋转整个画布呢?因为我要将这个旋转后的图像叠加在其他大图像上。 - Khawar
2
我所说的画布,指的是图像保存在其中的内存。你可以旋转你的电脑... 呃,不,按照我定义画布的方式,你不能旋转它。 ;) 在这种情况下,原始图像的画布也是另一个图像的画布,因为你想要将其绘制(并旋转)到上面。 - Nippey
这是我正在做的,你有什么建议? - Khawar
2
我已经改变了画布的物理 [大小] (http://www.freeimagehosting.net/b36kv),但是图像没有移动到中心,如何使其居中并且背景也应该是透明的? - Khawar
4
为什么这会是一个重复的问题?我的旋转角度可以是任意角度,而不仅仅是90度。我只是不想使用转置方法将图像旋转90度。 - Khawar
1个回答

2

我刚刚阅读了文档:ImgProc.warpAffine

仅摘录:

void warpAffine(InputArray src, OutputArray dst, InputArray M, Size dsize, [...]);
//Parameters: dsize – Size of the destination image.

请尝试以下操作:
Imgproc.warpAffine(cvImage, dummy, rotImage, dummy.size());

为了改变透明度,请在末尾调整参数:

Imgproc.warpAffine(cvImage, dummy, rotImage, dummy.size(), INTER_LINEAR, BORDER_TRANSPARENT);

1
Imgproc.warpAffine(cvImage,dummy,rotImage,dummy.size()); 注意:这是代码行,并非自然语言文本。 - Khawar
1
嗯?我写错了什么吗? :) - Nippey
不,我的意思是结果是一样的!如果使用INTER_LINEAR和BORDER_TRANSPARENT,那么它会将旋转后的图像写在原始图像(本身)上:( - Khawar
1
Imgproc.warpAffine(scaledImage, dummy, rotImage, dummy.size(), Imgproc.INTER_LINEAR, Imgproc.BORDER_TRANSPARENT, new Scalar(0)); 这段代码的结果 - Khawar
很抱歉,我要说这超出了我的能力范围。我目前没有可测试代码的运行环境 :/ - Nippey
很高兴你尝试帮忙..谢谢,我会努力解决并在有结果时发布答案.. - Khawar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接