영상에 문자열을 이용하여 필요한 정보를 표시해야 하는 경우가 있습니다.
OpenCV에서는 영상에 문자열을 출력할 수 있는 cv::putText()를 제공합니다.
cv::putText는 다음과 같은 인자를 받을 수 있습니다.
src
|
문자열을 출력할 영상
|
text
|
출력할 문자열, const String&
|
pos
|
문자열 출력할 위치의 좌하단 좌표, cv::Point
|
fontFace
|
폰트 종류, cv::HersheyFonts에서 선택 가능
|
fontScale
|
폰트 크기 확대 축소 비율
|
color
|
문자열 색상
|
thickness
|
문자열 선 두께
|
lineType
|
선타입, LINE_4, LINE_8, LINE_AA
|
bottomleftOrigin
|
true: 영상 좌하단을 원점으로, false: 영상 좌상단이 원점으로
|
여기에서 cv::HERSHEY 에 어떠한 종류의 글씨체가 있는지 살펴보면,
FONT_HERSHEY_SIMPLEX
|
설명 보다는
직접 영상으로 확인하는 것이 좋을 것 같아요. |
FONT_HERSHEY_PLAIN
|
|
FONT_HERSHEY_COMPLEX
|
|
FONT_HERSHEY_TIRPLEX
|
|
FONT_HERSHEY_COMPLEX_SMALL
|
|
FONT_HERSHEY_SCRIPT_SIMPLEX
|
|
FONT_HERSHEY_SCRIPT_COMPLEX
|
|
FONT_ITALIC
|
소스는 아래와 같습니다.
#include <iostream>
#include <opencv2/opencv.hpp>
int main()
{
cv::Mat src(500, 800, CV_8UC3, cv::Scalar(255, 255, 255));
cv::putText(src, "FONT_HERSHEY_SIMPLEX", cv::Point(20, 50), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(0, 0, 255));
cv::putText(src, "FONT_HERSHEY_PLAIN", cv::Point(20, 100), cv::FONT_HERSHEY_PLAIN, 1, cv::Scalar(0, 255, 0));
cv::putText(src, "FONT_HERSHEY_DUPLEX", cv::Point(20, 150), cv::FONT_HERSHEY_DUPLEX, 1, cv::Scalar(255, 0, 0));
cv::putText(src, "FONT_HERSHEY_COMPLEX", cv::Point(20, 200), cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 0, 255));
cv::putText(src, "FONT_HERSHEY_TRIPLEX", cv::Point(20, 250), cv::FONT_HERSHEY_TRIPLEX, 1, cv::Scalar(0, 255, 255));
cv::putText(src, "FONT_HERSHEY_COMPLEX_SMALL", cv::Point(20, 300), cv::FONT_HERSHEY_COMPLEX_SMALL, 1, cv::Scalar(255, 255, 0));
cv::putText(src, "FONT_HERSHEY_SCRIPT_SIMPLEX", cv::Point(20, 350), cv::FONT_HERSHEY_SCRIPT_SIMPLEX, 1, cv::Scalar(0, 0, 255));
cv::putText(src, "FONT_HERSHEY_SCRIPT_COMPLEX", cv::Point(20, 400), cv::FONT_HERSHEY_SCRIPT_COMPLEX, 1, cv::Scalar(100, 100, 100));
cv::putText(src, "FONT_HERSHEY_TRIPLEX | FONT_ITALIC", cv::Point(20, 450), cv::FONT_HERSHEY_TRIPLEX | cv::FONT_ITALIC, 1, cv::Scalar(0, 0, 0));
return 0;
}
결과 영상을 보면, 이런 글씨체들이 있습니다.
여러 문자열을 여러 줄로 출력할 경우 위의 예시처럼
pos 에 숫자를 넣어줄 수 없습니다. 이럴 때 어떻게 하느냐?
문자열 사각형의 크기를 알 수 있는 getTextSize()라는 함수를 제공하고 있습니다.
text
|
출력할 문자열
|
fontFace
|
폰트 종류
|
fontScale
|
폰트 크기 확대 축소 비율
|
thickness
|
문자열 선 두께
|
baseLine
|
가장 하단의 텍스트 위치 기준으로 기준선의 y좌표, 필요 없으면 0 입력
|
반환값
|
cv::Size 로 사각형의 크기 반환
|
이걸 응용하면 영상의 중앙에 글씨를 출력할 수 있습니다.
150 x 800 짜리 흰 배경 영상을 하나 만들고 그 위에 글씨를 적은 것 입니다.
#include <iostream>
#include <opencv2/opencv.hpp>
int main()
{
int width = 800;
int height = 150;
cv::Mat src(height, width, CV_8UC3, cv::Scalar(255, 255, 255));
std::string str = "JK Garden, Landscape Tree";
int fontFace = cv::FONT_HERSHEY_SIMPLEX;
double fontScale = 1.3;
int thickness = 2;
cv::Size szText = cv::getTextSize(str, fontFace, fontScale, thickness, 0);
cv::Point pos((width - szText.width) / 2, (height - szText.height) / 2);
cv::putText(src, str, pos, fontFace, fontScale, cv::Scalar(0, 0, 255), thickness);
return 0;
}
결과 영상은 아래와 같습니다.
여기서 꿀팁 대 방출~!!
font color를 매번 cv::Scalar(0,0,255) 이런 식으로 설정한다면 복잡하게 됩니다.
따라서 아래와 같이 미리 color 값을 정의 해 놓는다든지,
아니면 각 값을 0~255 값을 가지는 random 변수를 생성하면 편리해집니다.
cv::Scalar color[] = { {0, 0, 255}, // red
{0, 255, 0}, // green
{255, 0, 0}, // blue
{255, 255, 255}, // white
{255, 0, 255}, // magenta
{255, 255, 0}, // cyan
{0, 165, 255}, // orange
{0, 255, 255}, // yellow
{128, 0, 255},
{255, 128, 64} };
만약 영상의 color와 font color가 유사하다면? 문자열의 시인성이 떨어집니다.
그럴 경우 글상자에 background color를 넣으면 해결 될꺼에요.
cv::rectangle()을 사용하여 글자 크기에 맞도록 사각박스를 그린 후 글자를 출력하면
시인성 문제는 없어질 꺼에요. 이 것들을 조합하여 아래와 같은 함수 하나를 만들어봤어요.
이 함수를 이용하여 간단히 영상에 문자열을 출력해 보면, 전체 소스는 아래와 같고,
#include <iostream>
#include <opencv2/opencv.hpp>
#include <vector>
cv::Scalar color[] = { {0, 0, 255}, // red
{0, 255, 0}, // green
{255, 0, 0}, // blue
{255, 255, 255}, // white
{255, 0, 255}, // magenta
{0, 165, 255}, // orange
{0, 255, 255}, // yellow
{255, 255, 0}, // cyan
{128, 0, 255},
{255, 128, 64} };
void putTextOnImage(cv::Mat& src, const std::string& label_in, const cv::Point& pt_in, const cv::Scalar& textColor,
const cv::Scalar& bgColor, const int& textLineNum = 0)
{
int fontFace = cv::FONT_HERSHEY_SIMPLEX;
double fontScale = 0.5;
int fontThickness = 1;
int baseline = 0;
cv::Point text_pos = pt_in;
cv::Size text = cv::getTextSize(label_in, fontFace, fontScale, fontThickness, &baseline);
if (textLineNum > 0)
text_pos += cv::Point(0, text.height * textLineNum + 7 * textLineNum);
if (bgColor.val[0] >= 0 && bgColor.val[1] >= 0 && bgColor.val[2] >= 0) {
cv::rectangle(src, cv::Point(0 + text_pos.x, text_pos.y - text.height - 1),
cv::Point(text.width + text_pos.x, text_pos.y + baseline + 1), bgColor, cv::FILLED);
}
cv::putText(src, label_in, text_pos, fontFace, fontScale, textColor, fontThickness, 8);
}
int main()
{
cv::Mat lena_color = cv::imread("./lena_color.bmp", cv::IMREAD_UNCHANGED);
std::vector<std::string> vecStr{ "1. Lena Color Image", "2. JK Garden", "3. Landscape Tree" };
for (int i = 0; i < static_cast<int>(vecStr.size()); ++i) {
putTextOnImage(lena_color, vecStr[i], cv::Point(10, 10), color[i], color[i + 3], i);
}
return 0;
}
결과는 아래와 같습니다.
여기서 잠깐~~
한글이 출력되는지 확인해봐야겠죠?
위 소스에 한글을 하나 넣어봤습니다. 그리고 출력해봤어요.
출력해보니 한글이 '????' 로 깨지는 것을 볼 수 있습니다.
한글은 유니코드 이고, OpenCV는 유니코드를 지원하지 않기 때문이죠.
그럼 어떻게 해결할 수 있을까요?
다음 번에 시간내어 설명 드릴께요~!