环境: win + opencv4.2 + visual studio 2017
先看效果图,旋转后四个角多余部分为透明状态:
方法1:
计算旋转后的图片的宽高,然后遍历原图像素点拷贝到旋转后的图相应位置。注意:imread的最后一个参数IMREAD_UNCHANGED表示带有alpha通道。也就是 原图Mat必须是4通道(BGRA)。
Mat RotateBGRA_Mat(cv::Mat img, float angle)
{
double a = sin(angle * CV_PI / 180);
double b = cos(angle * CV_PI / 180);
int width = img.cols;
int height = img.rows;
int width_rotate = int(height * fabs(a) + width * fabs(b));//旋转后的宽
int height_rotate = int(width * fabs(a) + height * fabs(b));旋转后的高
Mat retMat = Mat::zeros(Size(width_rotate, height_rotate), CV_8UC4);
float anglePI = angle * CV_PI / 180;
int xSm, ySm;
for (int i = 0; i < retMat.rows; i++)
for (int j = 0; j < retMat.cols; j++)
{
xSm = (int)((i - retMat.rows / 2)*cos(anglePI) - (j - retMat.cols / 2)*sin(anglePI) + 0.5);
ySm = (int)((i - retMat.rows / 2)*sin(anglePI) + (j - retMat.cols / 2)*cos(anglePI) + 0.5);
xSm += img.rows / 2;
ySm += img.cols / 2;
if (xSm >= img.rows || ySm >= img.cols || xSm <= 0 || ySm <= 0) {
retMat.at<Vec4b>(i, j) = Vec4b(0, 0);
}
else {
retMat.at<Vec4b>(i, j) = img.at<Vec4b>(xSm, ySm);
}
}
return retMat;
}
int main()
{
int rotation = 30;
Mat r_mat = imread("xxx\\p.png", IMREAD_UNCHANGED);
//1 when Mat is with alpha channel(BGRA)
Mat dstMat = RotateBGRA_Mat(r_mat, rotation);
imwrite("D:\\s.png", dstMat);
}
方法2:
对于没有alpha通道的图片,可手动去掉某个颜色使其透明。
const int color_drop = 20;
struct ForEachOperator
{
void operator ()(cv::Vec4b &pixel, const int *position) const
{
if (pixel[0] <= color_drop && pixel[1] <= color_drop && pixel[2] <= color_drop)
pixel[3] = 0;
}
};
Mat RotateBGR_Mat(cv::Mat img, float angle)
{
double a = sin(angle * CV_PI / 180);
double b = cos(angle * CV_PI / 180);
int width = img.cols;
int height = img.rows;
int width_rotate = int(height * fabs(a) + width * fabs(b));//旋转后的宽
int height_rotate = int(width * fabs(a) + height * fabs(b));旋转后的高
Mat retMat = Mat::zeros(Size(width_rotate, height_rotate), CV_8UC3);
float anglePI = angle * CV_PI / 180;
int xSm, ySm;
for (int i = 0; i < retMat.rows; i++)
for (int j = 0; j < retMat.cols; j++)
{
xSm = (int)((i - retMat.rows / 2)*cos(anglePI) - (j - retMat.cols / 2)*sin(anglePI) + 0.5);
ySm = (int)((i - retMat.rows / 2)*sin(anglePI) + (j - retMat.cols / 2)*cos(anglePI) + 0.5);
xSm += img.rows / 2;
ySm += img.cols / 2;
if (xSm >= img.rows || ySm >= img.cols || xSm <= 0 || ySm <= 0) {
retMat.at<Vec3b>(i, j) = Vec3b(0, 0);
}
else {
retMat.at<Vec3b>(i, j) = img.at<Vec3b>(xSm, ySm);
}
}
return retMat;
}
int main()
{
int rotatio
n = 30;
Mat r_mat = imread("xxx\\p.png");
Mat input_bgra;
Mat dstMat = RotateBGR_Mat(r_mat, rotation);
cvtColor(dstMat, input_bgra, CV_BGR2BGRA);
input_bgra.forEach<Vec4b>(ForEachOperator());
imwrite("D:\\ss.png", input_bgra);
}
方法3:
注意:原图Mat也必须是4通道(BGRA),否则四周多余部分将出现黑边
int main()
{
int rotation = 30;
//The Mat is must with alpha channel(BGRA)
Mat r_mat3= imread("xxx\\p.png",IMREAD_UNCHANGED);
double a = sin(rotation * CV_PI / 180);
double b = cos(rotation * CV_PI / 180);
int width = r_mat3.cols;
int height = r_mat3.rows;
int width_rotate = int(height * fabs(a) + width * fabs(b));//旋转后的宽
int height_rotate = int(width * fabs(a) + height * fabs(b));旋转后的高
Point center = Point(r_mat3.cols / 2, r_mat3.rows / 2);// 旋转中心
Mat map_matrix = getRotationMatrix2D(center, rotation, 1.0);
map_matrix.at<double>(0, 2) += (width_rotate - width) / 2; // 修改坐标偏移
map_matrix.at<double>(1, 2) += (height_rotate - height) / 2; // 修改坐标偏移
Mat rotateImg;
warpAffine(r_mat3, rotateImg, map_matrix, { width_rotate, height_rotate });
imwrite("D:\\sss.png", rotateImg);
}