Skip to content

Commit

Permalink
add code
Browse files Browse the repository at this point in the history
  • Loading branch information
jiasibo committed May 9, 2017
1 parent 2293afc commit 5f2e19a
Show file tree
Hide file tree
Showing 10 changed files with 1,270 additions and 0 deletions.
13 changes: 13 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
cmake_minimum_required(VERSION 3.8)
project(cvUniText)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -Wall -O3")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -Wall -O3")
include_directories(/usr/include/freetype2/)
find_package( OpenCV REQUIRED )

add_library(cvunitext SHARED cvUniText.cpp)
add_executable(main test.cpp)
target_link_libraries(main cvunitext)
target_link_libraries(cvunitext freetype ${OpenCV_LIBS})
235 changes: 235 additions & 0 deletions cvUniText.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
#include "cvUniText.hpp"
#include <cstdio>
#include "utf8.h"
#include <ft2build.h>
#include <freetype/freetype.h>

using namespace uni_text;

namespace uni_text {
class Impl {
public:
Impl(const std::string &font_face, int font_size);

~Impl();

void SetParam(int font_size, float interval_ratio = 0.1, float whitespace_ratio = 0.3, float alpha = 1);

cv::Rect PutText(cv::Mat &img, const std::string &text, cv::Point &org,
cv::Scalar &color, bool calc_size);

private:
cv::Rect _cvPutUniTextUCS2(cv::Mat &img, const std::u16string &text,
cv::Point &org, cv::Scalar &color, bool calc_size);

double _cvPutUniChar(cv::Mat &img, char16_t wc,
cv::Point &pos, cv::Scalar &color, bool calc_size);

FT_Library m_library;
FT_Face m_face;
int m_fontType;
cv::Scalar m_fontSize;
float m_fontDiaphaneity;
};
}

UniText::UniText(const std::string &font_face, int font_size) {
pimpl = std::unique_ptr<Impl>(new Impl(font_face, font_size));
}

UniText::~UniText() = default;

void UniText::SetParam(int font_size, float interval_ratio, float whitespace_ratio, float alpha) {
pimpl->SetParam(font_size, interval_ratio, whitespace_ratio, alpha);
}

cv::Rect UniText::PutText(cv::Mat& img, const std::string& text, cv::Point& org,
cv::Scalar& color, bool calc_size) {
return pimpl->PutText(img, text, org, color, calc_size);
}

Impl::Impl(const std::string& font_face, int font_size) {
if (FT_Init_FreeType(&m_library) != 0) {
fprintf(stderr, "Freetype init failed!\n");
abort();
}

if (FT_New_Face(m_library, font_face.c_str(), 0, &m_face) != 0) {
fprintf(stderr, "Freetype font load failed!\n");
abort();
}

m_fontType = 0;
m_fontSize[0] = font_size; //FontSize
m_fontSize[1] = 0.5; //whitechar ratio, such like ' '
m_fontSize[2] = 0.1; //inverval ratio, for each char.
m_fontDiaphaneity = 1;//alpha

FT_Set_Pixel_Sizes(m_face, (int) m_fontSize[0], 0);
}

Impl::~Impl() {
FT_Done_Face(m_face);
FT_Done_FreeType(m_library);
}

void Impl::SetParam(int font_size, float interval_ratio, float whitespace_ratio, float alpha) {
m_fontSize[0] = font_size; //FontSize
m_fontSize[1] = whitespace_ratio; //whitechar ratio, such like ' '
m_fontSize[2] = interval_ratio; //inverval ratio, for each char.
m_fontDiaphaneity = alpha;//alpha
FT_Set_Pixel_Sizes(m_face, (int) m_fontSize[0], 0);
}

double Impl::_cvPutUniChar(cv::Mat& img, char16_t wc,
cv::Point& pos, cv::Scalar& color, bool calc_size) {
// generate font bitmap from unicode
FT_GlyphSlot ft_slot;
// int ft_ascender;
int ft_bmp_height;
int ft_bmp_width;//0 when ' '
int ft_bmp_step;
int ft_bmp_left;
int ft_bmp_top;
unsigned char *ft_bmp_buffer;


double whitespace_width;
double interval_width;
double horizontal_offset;

//
// img coordinate
// 0------+ x
// |
// +
// y
//
//freetype bmp coordinate
// y
// +
// |
// 0------+ x
//
//freetype algin
// 'a'
// -+- -+-
// | |
// |height |top
// | |
// -baseline-: -+- -+-
//
// 'g'
// -+- -+-
// | |
// | |top
// | |
// -baseline-: |height -+-
// |
// -+-
//

//get font_id from database of char
// ft_ascender = m_face->size->metrics.ascender / 64;

FT_UInt glyph_index = FT_Get_Char_Index(m_face, wc);
//load bitmap font to slot
FT_Load_Glyph(m_face, glyph_index, FT_LOAD_DEFAULT);
//render to 8bits
FT_Render_Glyph(m_face->glyph, FT_RENDER_MODE_NORMAL);
ft_slot = m_face->glyph;
ft_bmp_width = ft_slot->bitmap.width;
ft_bmp_height = ft_slot->bitmap.rows;
ft_bmp_step = ft_slot->bitmap.pitch;
ft_bmp_buffer = ft_slot->bitmap.buffer;
ft_bmp_left = ft_slot->bitmap_left;
ft_bmp_top = ft_slot->bitmap_top;

#ifdef CVUNITEXT_DEBUG
if (wc < 256) {
printf(" %c: ", ((char*)&wc)[0]);
} else {
printf(" 0x%02x%02x: ", ((char*)&wc)[1] & 0xFF, ((char*)&wc)[0] & 0xFF);
}
printf("width %4d, height %4d, ", ft_bmp_width, ft_bmp_height);
printf("left %4d, ", ft_bmp_left);
printf("top %4d, ", ft_bmp_top);
printf("\n");
#endif

//calculate char width
whitespace_width = m_fontSize[0] * m_fontSize[1];
interval_width = m_fontSize[0] * m_fontSize[2];
if (ft_bmp_width != 0) {
horizontal_offset = ft_bmp_width + interval_width;
} else {
horizontal_offset = whitespace_width;
}

int loc_x = pos.x + ft_bmp_left;
int loc_y = pos.y + ft_bmp_height - ft_bmp_top;

if (calc_size) {
return horizontal_offset;
}

//draw font bitmap to opencv image
//(bmp_j,bmp_i) is freetype bitmap location
for (int bmp_i = 0; bmp_i < ft_bmp_height; ++bmp_i) {
for (int bmp_j = 0; bmp_j < ft_bmp_width; ++bmp_j) {
int bmp_valoff = bmp_i * ft_bmp_step + bmp_j;
unsigned int bmp_val = ft_bmp_buffer[bmp_valoff];
float bmp_valf = (float) bmp_val / 255 * m_fontDiaphaneity;
if (bmp_val == 0) {
continue;
}
//(img_x,img_y) is opencv bitmap location
int img_y = loc_y - (ft_bmp_height - 1 - bmp_i);
int img_x = loc_x + bmp_j;

//update pixel when location is valid
// alpha = font_bitmap_val / 255;
// pixel = alpha * color + (1 - alpha) * pixel;
if ((0 <= img_y) && (img_y < img.rows) && (0 <= img_x) && (img_x < img.cols)) {
unsigned char *data = img.ptr<unsigned char>(img_y);
for (int img_channel = 0; img_channel < img.channels(); img_channel++) {
data[img_x * img.channels() + img_channel] =
(1 - bmp_valf) * data[img_x * img.channels() + img_channel] +
bmp_valf * color[img_channel];
}
}
}
}

return horizontal_offset;
}

cv::Rect Impl::_cvPutUniTextUCS2(cv::Mat& img, const std::u16string& text,
cv::Point& org, cv::Scalar& color, bool calc_size) {
cv::Point pt0 = org;
cv::Point pt1 = org;
double offset;
cv::Rect rect;
int ascender = m_face->size->metrics.ascender / 64;
int descender = m_face->size->metrics.descender / 64;

for (unsigned int i = 0; i < text.size(); i++) {
offset = _cvPutUniChar(img, text[i], pt1, color, calc_size);
pt1.x += (int) offset;
}
rect.width = pt1.x - pt0.x;
rect.height = ascender - descender;
rect.x = pt0.x;
rect.y = pt0.y - descender;
return rect;
}

cv::Rect Impl::PutText(cv::Mat& img, const std::string& text, cv::Point &org,
cv::Scalar& color, bool calc_size) {
// std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
// std::u16string dest = convert.from_bytes(text);
std::u16string dest;
utf8::utf8to32(text.begin(), text.end(), std::back_inserter(dest));
cv::Rect sz = _cvPutUniTextUCS2(img, dest, org, color, calc_size);
return sz;
}
43 changes: 43 additions & 0 deletions cvUniText.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#ifndef CV_UNI_TEXT_HPP
#define CV_UNI_TEXT_HPP
#include <opencv2/opencv.hpp>
#include <string>
#include <memory>

namespace uni_text {
class Impl;

class UniText {
public:
/// Initialization
/// \param font_face: the file path of your font
/// \param font_size
UniText(const std::string &font_face, int font_size);
~UniText();

/// Detailed parameter of text rendering. Call this before drawing the text
/// \param font_size
/// \param interval_ratio: Ratio of character interval over character width
/// \param whitespace_ratio: Ratio of whitespace width over character width
/// \param alpha: Transparency. 1 means totally opaque.
void SetParam(int font_size, float interval_ratio = 0.1, float whitespace_ratio = 0.5, float alpha = 1);

/// Draw text on an Opencv Mat
/// \param img
/// \param utf8_text: Text encoded in utf8. (if it is hardcoded, make sure your source file is saved
/// with utf8 encoding.
/// \param org: The left-bottom point of the text. Notice some letters like 'g' may go under this point
/// \param color
/// \param calc_size: true -> return rect. False -> return rect and draw text.
/// Useful e.g. when you want to draw a rectangle under the text
/// \return The precise bounding box of the text in the image
cv::Rect PutText(cv::Mat &img, const std::string &utf8_text, cv::Point &org,
cv::Scalar &color, bool calc_size);

private:
/// Hide implementations
std::unique_ptr<Impl> pimpl;
};
}

#endif
43 changes: 43 additions & 0 deletions install/cvUniText.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#ifndef CV_UNI_TEXT_HPP
#define CV_UNI_TEXT_HPP
#include <opencv2/opencv.hpp>
#include <string>
#include <memory>

namespace uni_text {
class Impl;

class UniText {
public:
/// Initialization
/// \param font_face: the file path of your font
/// \param font_size
UniText(const std::string &font_face, int font_size);
~UniText();

/// Detailed parameter of text rendering. Call this before drawing the text
/// \param font_size
/// \param interval_ratio: Ratio of character interval over character width
/// \param whitespace_ratio: Ratio of whitespace width over character width
/// \param alpha: Transparency. 1 means totally opaque.
void SetParam(int font_size, float interval_ratio = 0.1, float whitespace_ratio = 0.5, float alpha = 1);

/// Draw text on an Opencv Mat
/// \param img
/// \param utf8_text: Text encoded in utf8. (if it is hardcoded, make sure your source file is saved
/// with utf8 encoding.
/// \param org: The left-bottom point of the text. Notice some letters like 'g' may go under this point
/// \param color
/// \param calc_size: true -> return rect. False -> return rect and draw text.
/// Useful e.g. when you want to draw a rectangle under the text
/// \return The precise bounding box of the text in the image
cv::Rect PutText(cv::Mat &img, const std::string &utf8_text, cv::Point &org,
cv::Scalar &color, bool calc_size);

private:
/// Hide implementations
std::unique_ptr<Impl> pimpl;
};
}

#endif
Binary file added install/wqy-microhei.ttc
Binary file not shown.
18 changes: 18 additions & 0 deletions test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//
// Created by mini on 2017/5/8.
//

#include <opencv2/opencv.hpp>
#include "cvUniText.hpp"
#include <iostream>

int main() {
cv::Mat img = cv::imread("/home/jiasibo/1.jpg");
uni_text::UniText uniText("/usr/share/fonts/wqy-microhei/wqy-microhei.ttc", 80);
cv::Point p(100, 100);
cv::Scalar color(0,255,0);
cv::Rect rect = uniText.PutText(img, "Hello, 哈哈哈哈哈嗝", p, color, false);
std::cout << rect << std::endl;
cv::imwrite("1.jpg", img);
return 0;
}
34 changes: 34 additions & 0 deletions utf8.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright 2006 Nemanja Trifunovic

/*
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/


#ifndef UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731
#define UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731

#include "utf8/checked.h"
#include "utf8/unchecked.h"

#endif // header guard
Loading

0 comments on commit 5f2e19a

Please sign in to comment.