cv::rotate仅支持90°倍数旋转,任意角度需用cv::getRotationMatrix2D配合cv::warpAffine,并设中心点为图像中心;resize缩放应区分size与fx/fy参数,下采样推荐INTER_AREA;仿射矩阵须用CV_64F类型,黑边问题通过borderMode和borderValue控制。

cv::rotate 只能做 90° 倍数旋转,真要任意角度得用 cv::warpAffine
很多人看到 cv::rotate 就以为能转任意角度,结果试了 cv::ROTATE_90_CLOCKWISE 以外的值直接编译失败——它只支持三个固定枚举值。真正可控角度的旋转,必须走仿射变换流程:cv::getRotationMatrix2D 构造矩阵,再用 cv::warpAffine 应用。
关键点在于旋转中心默认是图像左上角(0,0),不设成图像中心就会“偏出画布”。正确做法是传入 cv::Point2f(src.cols/2.f, src.rows/2.f) 作为中心点。
- 旋转矩阵的第三列控制平移,
cv::getRotationMatrix2D会自动算好,但如果你手动改矩阵,得注意第三列单位是像素,不是归一化坐标 - 插值方式默认是
cv::INTER_LINEAR,对旋转缩放够用;实时场景可降为cv::INTER_NEAREST加速,但边缘锯齿明显 - 目标图像尺寸不变时,旋转后内容可能被裁剪——需要提前用
cv::RotatedRect+boundingRect算外接矩形,再 resize 输出图像
cv::resize 缩放别只传 scale 值,dx/dy 和 size 要分清场景
cv::resize 看似简单,但参数选错会导致意外拉伸或模糊。核心是搞清两种调用方式的区别:
- 用
size参数(cv::Size):明确指定输出宽高,无视原图比例,适合 UI 图标适配等强制尺寸场景 - 用
fx/fy参数:按比例缩放,更常用;但注意fx=0.5是缩小一半,不是缩小到 0.5 像素——值小于 1 时建议加cv::INTER_AREA(专为下采样优化) - 如果同时传
size和非 1.0 的fx/fy,OpenCV 会以size为准,fx/fy被忽略(文档没明说,实测如此)
常见错误:缩放后图像发虚,大概率是用了 cv::INTER_LINEAR 下采样——换成 cv::INTER_AREA 能显著改善。
立即学习“C++免费学习笔记(深入)”;
仿射变换矩阵不能手算 3×3,要用 cv::getAffineTransform 或 cv::getRotationMatrix2D
OpenCV 的仿射变换只接受 2×3 矩阵(即 cv::Mat 类型为 CV_64F、大小为 2×3),不是常见的齐次 3×3。自己拼矩阵容易出错,尤其第三列的平移项符号和单位。
- 已知三个对应点(如原图三角形顶点 + 目标位置),用
cv::getAffineTransform自动生成矩阵,比手算安全得多 - 纯旋转/缩放/平移组合,优先用
cv::getRotationMatrix2D、cv::getScaleTransform(需 OpenCV 4.8+)或手动 compose:先cv::Mat::eye(2,3,CV_64F),再改元素 - 矩阵 dtype 必须是
CV_64F(double),传CV_32F可能导致结果偏移几个像素,尤其大图上肉眼可见
执行时记得传 cv::warpAffine 的 borderMode 参数,比如 cv::BORDER_REPLICATE 防止旋转后黑边炸开。
warpAffine 边缘黑边不是 bug,是默认填充色在作怪
旋转或倾斜后图像四角出现黑边,不是算法问题,而是 cv::warpAffine 默认用 cv::Scalar(0)(全黑)填充背景。业务中往往需要透明、白底或镜像延展。
- 填白色:加参数
borderValue=cv::Scalar(255,255,255) - 透明(需 4 通道图):确保输入是
CV_8UC4,填cv::Scalar(0,0,0,0) - 内容延展:用
cv::BORDER_REFLECT或cv::BORDER_WRAP,但要注意扭曲严重时会出现诡异拼接 - 最稳妥方案:先用
cv::warpAffine到足够大的临时图,再用cv::getRectSubPix截取有效区域,避免填色干扰
实际部署时,cv::warpAffine 的性能对 CPU 影响不小,如果只是固定角度旋转,预生成查找表(LUT)比实时计算矩阵快 2–3 倍,但代码复杂度上升——多数场景直接用现成函数更省心。


















