Last active
May 14, 2022 07:07
-
-
Save nomissbowling/0983a80b78e4a18ec4cb521b92c564b8 to your computer and use it in GitHub Desktop.
cvPutTextFontDC.cpp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
cvPutTextFontDC.cpp | |
"C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\bin\Hostx64\x64\cl.exe" | |
-source-charset:utf-8 -execution-charset:utf-8 | |
-EHsc -FecvPutTextFontDC.exe cvPutTextFontDC.cpp | |
-IC:\OpenCV3\include | |
-link | |
/LIBPATH:C:\OpenCV3\x64\vc15\lib | |
/LIBPATH:"C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\lib\x64" | |
/LIBPATH:"C:\Program Files (x86)\Windows Kits\10\Lib\10.0.17763.0\ucrt\x64" | |
/LIBPATH:"C:\Program Files (x86)\Windows Kits\10\Lib\10.0.17763.0\um\x64" | |
opencv_world3412.lib | |
gdi32.lib | |
del .\cvPutTextFontDC.obj | |
cvPutTextFontDC | |
addText namefont | |
https://qiita.com/fukushima1981/items/8abdb621c7969ebb8ac7 | |
putText JP fonts | |
w32 https://jitaku.work/it/category/image-processing/opencv/write_japanese/ | |
era 2020 (STB) https://qiita.com/hon_no_mushi/items/9b98d35ed0b2263c437b | |
era 2020 (STB) https://qiita.com/hon_no_mushi/items/b139df3dcf6559404b3f | |
era 2016 https://qiita.com/hon_no_mushi/items/fe25c9e29219a6e56c3f | |
era 2016 https://qiita.com/hon_no_mushi/items/c34a07331effced545fb | |
py https://qiita.com/mo256man/items/b6e17b5a66d1ea13b5e3 | |
py https://qiita.com/mo256man/items/82da5138eeacc420499d | |
py https://qiita.com/goodboy_max/items/d5e7f1c0ecd3d446c4d0 | |
*/ | |
#define UNICODE | |
#define _UNICODE | |
#include <wchar.h> | |
// use CV_PI instead of M_PI | |
// #define _USE_MATH_DEFINES | |
#include <opencv2/opencv.hpp> | |
// #include <opencv2/imgproc.hpp> // cv::FONT *, cv::LINE *, cv::FILLED | |
#include <iomanip> | |
#include <iostream> | |
#include <sstream> | |
#include <map> | |
#include <vector> | |
#include <string> | |
#include <stdexcept> | |
#include <exception> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <windows.h> | |
#define BASEDIR "E:\\virtual2\\SlowShutter\\" | |
#define V_W 640 | |
#define V_H 480 | |
#define OUTDIR BASEDIR | |
#define IM_W 640 | |
#define IM_H 480 | |
#define BASECOUNT 40000 | |
#define BREAKCOUNT 600 // when NOWAIT (600/24sec 1536KB) (save 10fps:60frms) | |
// #define NOWAIT // NOWAIT: <30fps, no NOWAIT: <17fps (depends on CPU) | |
#define FILE_IN BASEDIR"contours_iroha.png" | |
using namespace std; | |
uint8_t COLS[][3] = { // RGB | |
{240, 192, 32}, {32, 240, 192}, {192, 32, 240}, {255, 255, 255}, | |
{240, 32, 192}, {192, 240, 32}, {32, 192, 240}, {0, 0, 0}}; | |
vector<cv::Scalar> createColors() | |
{ | |
vector<cv::Scalar> colors(_countof(COLS)); | |
int i = 0; | |
for(auto it = colors.begin(); it != colors.end(); ++it, ++i) | |
*it = cv::Scalar(COLS[i][2], COLS[i][1], COLS[i][0]); // BGR | |
return colors; | |
} | |
template<typename ... Args> | |
std::string format(const std::string &fmt, Args ... args) | |
{ | |
size_t len = std::snprintf(nullptr, 0, fmt.c_str(), args ...); | |
std::vector<char> buf(len + 1); | |
std::snprintf(&buf[0], len + 1, fmt.c_str(), args ...); | |
return std::string(&buf[0], &buf[0] + len); | |
} | |
template<typename ... Args> | |
void putFmtTxt(cv::Mat &dst, cv::Point &pos, cv::Scalar &col, | |
const std::string &fmt, Args ... args) | |
{ | |
const string &txt = format(fmt, args ...); | |
const int th = 1; | |
const double fs = 1.0; | |
const int ff = cv::FONT_HERSHEY_PLAIN; | |
// const cv::FontFace ff("timesnewroman.ttf"); // only new version | |
cv::Scalar &dc = cv::Scalar(255, 255, 255) - col; | |
cv::putText(dst, txt, pos, ff, fs, dc, th + 1, cv::LINE_AA); | |
cv::putText(dst, txt, pos, ff, fs, col, th, cv::LINE_AA); | |
// cv::addText(dst, txt, pos, "Consolas", fs, col, th, cv::LINE_AA); // Qt | |
} | |
inline unsigned int calcW(BITMAP *pbm, unsigned int w) | |
{ | |
return ((pbm->bmBitsPixel / 8) * w) & ~3; | |
} | |
void dcPutText(cv::Mat &dst, const string &txt, const cv::Point &pos, | |
const string &fontname, double fontScale, const cv::Scalar &color) | |
{ | |
int bgc = 0xff; | |
int fontSize = (int)(16 * fontScale); | |
int height = fontSize * 3 / 2; | |
int width = dst.cols; | |
HDC mdc = CreateCompatibleDC(NULL); | |
BITMAPINFOHEADER bmih; | |
memset(&bmih, 0, sizeof(BITMAPINFOHEADER)); | |
bmih.biSize = sizeof(BITMAPINFOHEADER); | |
bmih.biWidth = width; | |
bmih.biHeight = height; | |
bmih.biPlanes = 1; | |
bmih.biBitCount = 24; | |
BITMAPINFO bmi; | |
bmi.bmiHeader = bmih; | |
HBITMAP hbmp = CreateDIBSection(NULL, &bmi, DIB_RGB_COLORS, NULL, NULL, 0); | |
HBITMAP obmp = (HBITMAP)SelectObject(mdc, hbmp); | |
BITMAP bm; | |
GetObject(hbmp, sizeof(bm), &bm); | |
int mw = calcW(&bm, width), mh = dst.rows; | |
int bw = calcW(&bm, bm.bmWidth), bh = bm.bmHeight; | |
memset(bm.bmBits, bgc, mw * height); | |
#if 0 // mw: 1920(=640x3) bw: 1920 bh: 48 | |
fprintf(stdout, "bmBits: %p mw: %d bw: %d bh: %d\n", bm.bmBits, mw, bw, bh); | |
#endif | |
HFONT hFont = CreateFontA( | |
fontSize, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, | |
SHIFTJIS_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, | |
VARIABLE_PITCH | FF_ROMAN, fontname.c_str()); | |
HFONT oFont = (HFONT)SelectObject(mdc, hFont); | |
TextOutA(mdc, 0, height / 3 * 1, txt.c_str(), (int)txt.length()); | |
#if 0 | |
fprintf(stdout, "hFont: %p oFont: %p txt[%s]\n", hFont, oFont, txt.c_str()); | |
#endif | |
int posX = pos.x, posY = pos.y - fontSize; | |
for(int y = 0; y < bh; ++y){ | |
if(posY + y < 0 && posY + y >= mh) break; | |
BYTE *img = dst.data + (posY + y) * mw + posX * 3; | |
BYTE *bp = (BYTE *)bm.bmBits + (bh - y - 1) * bw; | |
for(int x = 0; x < bm.bmWidth; ++x){ | |
if(posX + x >= width) break; | |
#if 0 | |
if(x >= fontSize) break; | |
fprintf(stdout, "%s", (bp[0] | bp[1] | bp[2]) < 0x44 ? "*" : " "); | |
if(x == fontSize - 1) fprintf(stdout, "\n"); | |
#endif | |
#if 0 | |
if((*bp++ | *bp++ | *bp++) < 0x44) // (!(*bp++ | *bp++ | *bp++)) | |
for(int c = 0; c < 3; ++c) *img++ = (BYTE)color.val[c]; | |
else img += 3; | |
#else | |
for(int c = 0; c < 3; ++c){ | |
BYTE s = *img; | |
double a = (255 - *bp++) / 255.0; | |
*img++ = (BYTE)(a * (BYTE)color.val[c] + (1.0 - a) * s); | |
} | |
#endif | |
} | |
} | |
SelectObject(mdc, oFont); | |
DeleteObject(hFont); | |
SelectObject(mdc, obmp); | |
DeleteObject(hbmp); | |
DeleteDC(mdc); | |
} | |
int main(int ac, char **av) | |
{ | |
fprintf(stdout, "sizeof(size_t): %zu\n", sizeof(size_t)); | |
vector<cv::Scalar> colors = createColors(); | |
cv::Mat src = cv::imread(FILE_IN); | |
cv::resize(src, src, cv::Size(IM_W, IM_H), 0, 0, cv::INTER_LANCZOS4); | |
cv::Mat dst; | |
cv::cvtColor(src, dst, cv::COLOR_BGR2GRAY); // CV_8UC3 -> CV_8UC1 | |
cv::threshold(dst, dst, 127.0, 255.0, cv::THRESH_BINARY | cv::THRESH_OTSU); | |
dst = ~dst; | |
#if 0 | |
cv::cvtColor(dst, dst, cv::COLOR_GRAY2BGR); | |
#else | |
vector<cv::Mat> bgr{ // BGR | |
cv::Mat::ones(dst.size(), dst.type()) * 32, // CV_8UC1 | |
cv::Mat::ones(dst.size(), dst.type()) * 192, // CV_8UC1 | |
dst * 240 / 255}; // CV_8UC1 | |
cv::merge(bgr, dst); // CV_8UC3 | |
#endif | |
const char *cp932 = "\x82\x63\x82\x65\x97\xed\x89\xeb\x91\x76"; // DFLGS | |
// const char *cp932 = "Consolas"; // Consolas | |
const string txt(cp932); | |
const string fontname(cp932); | |
dcPutText(dst, txt, cv::Point{160, 120}, fontname, 2.0, colors[2]); | |
vector<string> wn({"Src", "Gray", "Diff", "KpPk", "Mask", "Dst"}); | |
for(vector<string>::iterator i = wn.begin(); i != wn.end(); ++i) | |
cv::namedWindow(*i, CV_WINDOW_AUTOSIZE | CV_WINDOW_FREERATIO); | |
int cam_id = 0; // 1; // 0; // may be 'ManyCam Virtual Webcam' | |
int width = IM_W, height = IM_H, fourcc; | |
double fps = 10.0; // 30.0; | |
cv::VideoCapture cap(cv::CAP_DSHOW + cam_id); // cap(FN); | |
if(!cap.isOpened()) return 1; | |
fprintf(stdout, "width: %d, height %d\n", | |
(int)cap.get(cv::CAP_PROP_FRAME_WIDTH), | |
(int)cap.get(cv::CAP_PROP_FRAME_HEIGHT)); | |
// save to .mp4 and convert .mp4 by ShinkuSuperLite | |
fourcc = cv::VideoWriter::fourcc('m', 'p', '4', 'v'); // OK .p4 (mp4v) | |
// fourcc = cv::VideoWriter::fourcc('X', 'V', 'I', 'D'); // OK must save .avi | |
// fourcc = cv::VideoWriter::fourcc('X', '2', '6', '4'); // OK .avi need .dll | |
// fourcc = cv::VideoWriter::fourcc('H', '2', '6', '4'); // OK .avi need .dll | |
// fourcc = 0x00000020; // fallback tag | |
bool col = true; | |
cv::VideoWriter wr(OUTDIR"_w32.mp4", fourcc, fps, cv::Size(IM_W, IM_H), col); | |
cv::Mat frm(V_H, V_W, CV_8UC3); | |
cv::Mat gry(IM_H, IM_W, CV_8UC1); // to CV_8UC3 | |
cv::Mat img(IM_H, IM_W, CV_8UC3); | |
int cnt = BASECOUNT; | |
while(cap.read(frm)){ | |
cv::GaussianBlur(frm, frm, cv::Size(3, 3), 0); | |
cv::Mat tmp; | |
cv::resize(frm, tmp, cv::Size(IM_W, IM_H), 0, 0, cv::INTER_LANCZOS4); | |
if(cnt == BASECOUNT) tmp.copyTo(img); | |
cv::cvtColor(tmp, gry, cv::COLOR_BGR2GRAY); // CV_8UC1 | |
cv::cvtColor(gry, gry, cv::COLOR_GRAY2BGR); // CV_8UC3 | |
cv::imshow("Src", tmp); | |
cv::imshow("Gray", gry); | |
cv::imshow("Diff", dst); | |
int fromto[] = {0, 1, 1, 0, 2, 2}; // 0->1 1->0 2->2 | |
cv::mixChannels(dst, img, fromto, _countof(fromto) / 2); | |
cv::imshow("Dst", img); | |
wr << img; | |
++cnt; | |
int k = cv::waitKey(1); // 1ms > 15ms ! on Windows | |
if(k == 'q' || k == '\x1b') break; | |
} | |
wr.release(); | |
cap.release(); | |
cv::destroyAllWindows(); | |
fprintf(stdout, "frames: %d\n", cnt); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment