Skip to content

Instantly share code, notes, and snippets.

@nomissbowling
Last active May 14, 2022 07:07
Show Gist options
  • Save nomissbowling/0983a80b78e4a18ec4cb521b92c564b8 to your computer and use it in GitHub Desktop.
Save nomissbowling/0983a80b78e4a18ec4cb521b92c564b8 to your computer and use it in GitHub Desktop.
cvPutTextFontDC.cpp
/*
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