文章目录
- ● opencv文字旋转 putText旋转90°
- 1. cv::getTextSize获取文字的尺寸textSize
- 2. 设置文字图像textImg尺寸格式
- 3. 将文字绘制在文字图像textImg上
- 4. 对文字图像textImg进行旋转
- 5. 在原图img上设置用来放置文字图像textImg的roi区域
- 5.1 矩形区域roi
- 5.2 行列范围roi
- 6. 将文字图像textImg放置在roi区域上
- 6.1 copyTo
- 6.1.1 不设置掩膜
- 6.2.2 设置掩膜
- 6.2 `+` / `add()`
- 7. 整体流程代码
● opencv文字旋转 putText旋转90°
- putText本身不支持对文字进行旋转,所以将文字写在图像上,将图像进行旋转后再贴到原如上(可设置掩膜),以实现文字旋转的效果
1. cv::getTextSize获取文字的尺寸textSize
std::string text="treeAndCat";
int fontFace=cv::FONT_HERSHEY_SIMPLEX;//字体
double fontScale=2;//缩放系数
cv::Scalar color=cv::Scalar(255,255,255);//颜色
int thickness = 4;//线条粗细
int lineType = 8;//线型
int baseLine;//相当于四线格的第三行高度
cv::Size textSize = cv::getTextSize(text, fontFace, fontScale, thickness, &baseLine);
2. 设置文字图像textImg尺寸格式
cv::Mat textImg=cv::Mat::zeros(textSize.height+baseLine,textSize.width,/*CV_8UC1*/img.type());
textSize.width
文字的宽度textSize.height
文字的高度(相当于四线格的第一第二行高度)baseLine
基线相对于最底部文本点的y坐标(相当于四线格的第三行高度)- 所以在设置文字的roi时高度应该是
textSize.height+baseLine
- 尤其是文字中含fgjpqy字母时不要忘记加baseLine
- 虽然纯数字不含fgjpq但
cv::getTextSize
计算出的baseLine也不为0
- 所以在设置文字的roi时高度应该是
3. 将文字绘制在文字图像textImg上
cv::putText(textImg,text,cv::Point(0,textSize.height+0.5*baseLine),fontFace,fontScale,color,thickness,lineType);
- 注意putText第三个参数为
左下角坐标
不是左上角 - 因为不含fgjpq不担心超出,这里再加上了
0.5*baseLine
,是为了在文字上下各留0.5*baseLine
的空白,(倘若含fgjpq就不要加0.5*baseLine
了,上方会超出图像)
- 注意putText第三个参数为
-
一开始误将坐标写为左上角坐标导致textImg基本没有写到文字
-
putText第三个参数的y坐标一开始设为textSize.height没加0.5*baseLine,导致文字底端紧贴图像底部,上方仍有空余不美观
-
第三个参数设置为cv::Point(0,textSize.height+baseLine)的效果
-
第三个参数设置为cv::Point(0,textSize.height+0.5*baseLine)的效果
4. 对文字图像textImg进行旋转
cv::rotate(textImg,textImg,cv::ROTATE_90_COUNTERCLOCKWISE);
cv::ROTATE_90_COUNTERCLOCKWISE
逆时针旋转90°cv::ROTATE_90_CLOCKWISE
顺时针旋转90°
5. 在原图img上设置用来放置文字图像textImg的roi区域
5.1 矩形区域roi
cv::Mat textRoi=img(cv::Rect(leftTopPoint.x,leftTopPoint.y,width,height));
- cv::Rect里的参数分别为 左上角坐标x,y值以及区域宽高
5.2 行列范围roi
cv::Mat textRoi=img(cv::Range(rowStart,rowEnd),cv::Range(colStart,colEnd));
- cv::Range里的参数分别为起止行,列;注意不包含结束行/列,相当于左闭右开 [start,end)
6. 将文字图像textImg放置在roi区域上
6.1 copyTo
6.1.1 不设置掩膜
textImg.copyTo(textRoi);
- 会将整个textImg贴在原图roi处,textImg上非文字部分的图像可能会遮住原图的部分信息,如下图
- 会将整个textImg贴在原图roi处,textImg上非文字部分的图像可能会遮住原图的部分信息,如下图
6.2.2 设置掩膜
textImg.copyTo(textRoi,textImg);
- 由于textImg设置了黑底白字,所以可以直接用它本身当掩膜(textRoi上只显示textImg在掩膜上不为0的像素),即只将textImg图像上的文字贴在了原图上
- 由于textImg设置了黑底白字,所以可以直接用它本身当掩膜(textRoi上只显示textImg在掩膜上不为0的像素),即只将textImg图像上的文字贴在了原图上
- 另一种掩膜思路(这个复杂一点 可结合思考copyTo的掩膜)
- 将水印加在原图上,对于需要作为水印的图,首先将这张图由
彩色图
转换为单通道灰度图
,再利用阈值将灰度图转换为二值图
,那么这张二值图就会成为掩膜;在原图上取与掩膜图同样大小的roi
区域;对两张图进行按位与bitwise_and
(有0为0),掩膜上的黑色区域在roi上也是黑色的;其次对掩膜进行非运算取反操作bitwise_not
(掩膜黑白颠倒),再将掩膜与水印图进行位与bitwise_and
(掩膜上的黑色区域在水印图上也是黑色的,非黑色部分正好是roi上的黑色区域),最后将进行了掩膜的roi与水印图相加add()
- 将水印加在原图上,对于需要作为水印的图,首先将这张图由
6.2 +
/ add()
-
图像+图像
img1=img2+img3;
- 相加图像尺寸应相同,相同位置像素值相加(单通道灰度图为对应位置像素的灰度值相加,多通道为各通道的每个像素值相加)
-
图像+标量
img1=img2+a;
- img2各通道的每个像素值加a
-
+
和add()
的区别+
:sum=mod(a+b,256)
(取模操作,超出255的取模,如和为300最后sum就为45;直接使加法时需谨慎,超出255的话很亮的区域反而变暗了)add()
:sum=a+b>255 ? 255:a+b
(饱和操作,超出255的设为255)
void cv::add(InputArray src1,InputArray src2,OutputArray dst,InputArray mask = noArray(),int dtype = -1)
7. 整体流程代码
//获取文字尺寸
cv::Size textSize = cv::getTextSize(text, fontFace, fontScale, thickness, &baseLine);
//创建文字图像
cv::Mat textImg=cv::Mat::zeros(textSize.height+baseLine,textSize.width,img.type());
//将文字写到图像上
cv::putText(textImg,text,cv::Point(0,textSize.height+0.5*baseLine),fontFace,fontScale,color,thickness,lineType);
//对图像进行旋转
cv::rotate(textImg,textImg,cv::ROTATE_90_COUNTERCLOCKWISE);
//在原图上取图像大小roi
cv::Mat textRoi=img(cv::Rect(leftTopPoint.x,leftTopPoint.y,textImg.size().width,textImg.size().height));
//将文字图像贴到原图上
textImg.copyTo(textRoi,textImg);
//或者使用add()与上方代码效果相同(因为我的图是黑底白字的,其他颜色的可能会有些区别)
//cv::add(textImg,textRoi,textRoi);
//textRoi=textRoi+textImg;
-
最终效果图 将文字横着写在图像竖线上方