opencv 写中文到图片上 网上有很多都是本地安装的 然后配合freetype工作 javacv使用的是javacpp 不能用c/c++的直接解决方案, 翻看了opencv的各个modules 发现在opencv_contrib的modules下有freetype这个模块
下载源码
然后 vim opencv/cppbuild.sh 找到 找到并打开freetype模块的编译
BUILD_CONTRIB_X=".... -DBUILD_opencv_dnn_modern=OFF -DBUILD_opencv_freetype=ON-DBUILD_opencv_dpm=OFF -DBUILD_opencv_face=ON -DBUILD_opencv_hfs=OFF -DBUILD_opencv_latentsvm=OFF ....."
可能mvn仓库中没有SNAPSHOT的 javacpp 可以将源码一并clone下来 然后手工编译
cd javacpp
mvn install -DskipTests
mvn install -DskipTests -pl .,opencv
然后会下载opencv的 c++版本库
等下载解压完 用等mvn 编译完(需要很长时间) 下载玩完就可以先停掉 (机器好的可以忽略哈) 实际可能并没有编译freetype模块
下面有些细节
修改上面的cppbuild.sh 后 mvn构建会将freetype和harfbuzz加入构建

依赖 freetype harfbuzz 可以先 brew install freetype harfbuzz(maxos) 确保 freetype在 待构建的列表中(如果本地没有安装freetype harfbuzz 很可能出现在 Unavaliable的列表里)

然后再下面的构建中可以看到

然而按照上面编译完成 还是没法用freetype 因为没有添加java的接口
添加如下的映射类
javacpp-presets/opencv/src/main/java/org/bytedeco/javacpp/presets/opencv_freetype.java
package org.bytedeco.javacpp.presets;
import org.bytedeco.javacpp.annotation.Platform;
import org.bytedeco.javacpp.annotation.Properties;
import org.bytedeco.javacpp.tools.InfoMap;
import org.bytedeco.javacpp.tools.InfoMapper;
@Properties(
inherit = {opencv_core.class,opencv_imgproc.class},
value = {
@Platform(
include = {""},
link = "opencv_freetype@.3.4"
),
@Platform(value = "ios", preload = "libopencv_freetype"),
@Platform(value = "windows", link = "opencv_freetype342")
},
target = "org.bytedeco.javacpp.opencv_freetype"
)
public class opencv_freetype implements InfoMapper {
@Override public void map(InfoMap infoMap) {
}
后面会自动根据 freetype.cpp 接口文件 生成 javacpp-presets/opencv/src/main/java/org/bytedeco/javacpp/presets/opencv_freetype.java 详细的方法映射文件(一开始我也以为要自己手写 后面按照其他文件的方式随便写了一个可以编译的 mvn package的时候就被自动生成的给覆盖了 应该不用自己写 可以自动生成的)

Cpp 文件在javacpp-presets/opencv/cppbuild/macosx-x86_64/opencv_contrib-3.4.2/modules/freetype/include/opencv2/freetype.hpp
这个接口文件可以看下
namespace cv {
namespace freetype {
//! @addtogroup freetype
//! @{
class CV_EXPORTS_W FreeType2 : public Algorithm
{
public:
/** @brief Load font data.
The function loadFontData loads font data.
@param fontFileName FontFile Name
@param id face_index to select a font faces in a single file.
*/
CV_WRAP virtual void loadFontData(String fontFileName, int id) = 0;
/** @brief Set Split Number from Bezier-curve to line
The function setSplitNumber set the number of split points from bezier-curve to line.
If you want to draw large glyph, large is better.
If you want to draw small glyph, small is better.
@param num number of split points from bezier-curve to line
*/
CV_WRAP virtual void setSplitNumber( int num ) = 0;
/** @brief Draws a text string. 核心的就是这个可以写UTF编码的 默认opencv_imgproc.putText只能写ascii码
The function putText renders the specified text string in the image. Symbols that cannot be rendered using the specified font are replaced by "Tofu" or non-drawn.
@param img Image.
@param text Text string to be drawn.
@param org Bottom-left/Top-left corner of the text string in the image.
@param fontHeight Drawing font size by pixel unit.
@param color Text color.
@param thickness Thickness of the lines used to draw a text when negative, the glyph is filled. Otherwise, the glyph is drawn with this thickness.
@param line_type Line type. See the line for details.
@param bottomLeftOrigin When true, the image data origin is at the bottom-left corner. Otherwise, it is at the top-left corner.
*/
CV_WRAP virtual void putText(
InputOutputArray img, const String& text, Point org,
int fontHeight, Scalar color,
int thickness, int line_type, bool bottomLeftOrigin
) = 0;
/** @brief Calculates the width and height of a text string.
The function getTextSize calculates and returns the approximate size of a box that contains the specified text.
That is, the following code renders some text, the tight box surrounding it, and the baseline: :
@code
String text = "Funny text inside the box";
int fontHeight = 60;
int thickness = -1;
int linestyle = 8;
Mat img(600, 800, CV_8UC3, Scalar::all(0));
int baseline=0;
cv::Ptr<:freetype::freetype2> ft2;
ft2 = cv::freetype::createFreeType2();
ft2->loadFontData( "./mplus-1p-regular.ttf", 0 );
Size textSize = ft2->getTextSize(text,
fontHeight,
thickness,
&baseline);
if(thickness > 0){
baseline += thickness;
}
// center the text
Point textOrg((img.cols - textSize.width) / 2,
(img.rows + textSize.height) / 2);
// draw the box
rectangle(img, textOrg + Point(0, baseline),
textOrg + Point(textSize.width, -textSize.height),
Scalar(0,255,0),1,8);
// ... and the baseline first
line(img, textOrg + Point(0, thickness),
textOrg + Point(textSize.width, thickness),
Scalar(0, 0, 255),1,8);
// then put the text itself
ft2->putText(img, text, textOrg, fontHeight,
Scalar::all(255), thickness, linestyle, true );
@endcode
@param text Input text string.
@param fontHeight Drawing font size by pixel unit.
@param thickness Thickness of lines used to render the text. See putText for details.
@param[out] baseLine y-coordinate of the baseline relative to the bottom-most text
point.
@return The size of a box that contains the specified text.
@see cv::putText
*/
CV_WRAP virtual Size getTextSize(const String& text,
int fontHeight, int thickness,
CV_OUT int* baseLine) = 0;
};
/** @brief Create FreeType2 Instance
The function createFreeType2 create instance to draw UTF-8 strings.
*/
CV_EXPORTS_W Ptr createFreeType2();
//! @}
} } // namespace freetype
#endif
#endif
生成的java文件是这样的 javacpp-presets/opencv/src/main/java/org/bytedeco/javacpp/opencv_freetype.java
// Targeted by JavaCPP version 1.4.3-SNAPSHOT: DO NOT EDIT THIS FILE
package org.bytedeco.javacpp;
import java.nio.*;
import org.bytedeco.javacpp.*;
import org.bytedeco.javacpp.annotation.*;
import static org.bytedeco.javacpp.opencv_core.*;
import static org.bytedeco.javacpp.opencv_imgproc.*;
public class opencv_freetype extends org.bytedeco.javacpp.presets.opencv_freetype {
static { Loader.load(); }
// Parsed from
//################################################################################
//
// Created by Kumataro
//
//################################################################################
// #ifndef _OPENCV_FREETYPE_H_
// #define _OPENCV_FREETYPE_H_
// #ifdef __cplusplus
// #include
/**
\defgroup freetype Drawing UTF-8 strings with freetype/harfbuzz
This modules is to draw UTF-8 strings with freetype/harfbuzz.
1. Install freetype2 and harfbuzz in your system.
2. Create FreeType2 instance with createFreeType2() function.
3. Load font file with loadFontData() function.
4. Draw text with putText() function.
- If thickness parameter is negative, drawing glyph is filled.
- If thickness parameter is positive, drawing glyph is outlined with thickness.
- If line_type parameter is 16(or CV_AA), drawing glyph is smooth.
*/
/** \addtogroup freetype
* \{ */
@Namespace("cv::freetype") public static class FreeType2 extends Algorithm {
static { Loader.load(); }
/** Pointer cast constructor. Invokes {@link Pointer#Pointer(Pointer)}. */
public FreeType2(Pointer p) { super(p); }
/** \brief Load font data.
The function loadFontData loads font data.
@param fontFileName FontFile Name
@param id face_index to select a font faces in a single file.
*/
public native void loadFontData(@Str BytePointer fontFileName, int id);
public native void loadFontData(@Str String fontFileName, int id);
/** \brief Set Split Number from Bezier-curve to line
The function setSplitNumber set the number of split points from bezier-curve to line.
If you want to draw large glyph, large is better.
If you want to draw small glyph, small is better.
@param num number of split points from bezier-curve to line
*/
public native void setSplitNumber( int num );
/** \brief Draws a text string.
The function putText renders the specified text string in the image. Symbols that cannot be rendered using the specified font are replaced by "Tofu" or non-drawn.
@param img Image.
@param text Text string to be drawn.
@param org Bottom-left/Top-left corner of the text string in the image.
@param fontHeight Drawing font size by pixel unit.
@param color Text color.
@param thickness Thickness of the lines used to draw a text when negative, the glyph is filled. Otherwise, the glyph is drawn with this thickness.
@param line_type Line type. See the line for details.
@param bottomLeftOrigin When true, the image data origin is at the bottom-left corner. Otherwise, it is at the top-left corner.
*/
public native void putText(
@ByVal Mat img, @Str BytePointer text, @ByVal Point org,
int fontHeight, @ByVal Scalar color,
int thickness, int line_type, @Cast("bool") boolean bottomLeftOrigin
);
public native void putText(
@ByVal Mat img, @Str String text, @ByVal Point org,
int fontHeight, @ByVal Scalar color,
int thickness, int line_type, @Cast("bool") boolean bottomLeftOrigin
);
public native void putText(
@ByVal UMat img, @Str String text, @ByVal Point org,
int fontHeight, @ByVal Scalar color,
int thickness, int line_type, @Cast("bool") boolean bottomLeftOrigin
);
public native void putText(
@ByVal UMat img, @Str BytePointer text, @ByVal Point org,
int fontHeight, @ByVal Scalar color,
int thickness, int line_type, @Cast("bool") boolean bottomLeftOrigin
);
public native void putText(
@ByVal GpuMat img, @Str BytePointer text, @ByVal Point org,
int fontHeight, @ByVal Scalar color,
int thickness, int line_type, @Cast("bool") boolean bottomLeftOrigin
);
public native void putText(
@ByVal GpuMat img, @Str String text, @ByVal Point org,
int fontHeight, @ByVal Scalar color,
int thickness, int line_type, @Cast("bool") boolean bottomLeftOrigin
);
/** \brief Calculates the width and height of a text string.
The function getTextSize calculates and returns the approximate size of a box that contains the specified text.
That is, the following code renders some text, the tight box surrounding it, and the baseline: :
{@codeString text = "Funny text inside the box";
int fontHeight = 60;
int thickness = -1;
int linestyle = 8;
Mat img(600, 800, CV_8UC3, Scalar::all(0));
int baseline=0;
cv::Ptr<:freetype::freetype2> ft2;
ft2 = cv::freetype::createFreeType2();
ft2->loadFontData( "./mplus-1p-regular.ttf", 0 );
Size textSize = ft2->getTextSize(text,
fontHeight,
thickness,
&baseline);
if(thickness > 0){
baseline += thickness;
}
// center the text
Point textOrg((img.cols - textSize.width) / 2,
(img.rows + textSize.height) / 2);
// draw the box
rectangle(img, textOrg + Point(0, baseline),
textOrg + Point(textSize.width, -textSize.height),
Scalar(0,255,0),1,8);
// ... and the baseline first
line(img, textOrg + Point(0, thickness),
textOrg + Point(textSize.width, thickness),
Scalar(0, 0, 255),1,8);
// then put the text itself
ft2->putText(img, text, textOrg, fontHeight,
Scalar::all(255), thickness, linestyle, true );
}
@param text Input text string.
@param fontHeight Drawing font size by pixel unit.
@param thickness Thickness of lines used to render the text. See putText for details.
@param [out] baseLine y-coordinate of the baseline relative to the bottom-most text
point.
@return The size of a box that contains the specified text.
@see cv::putText
*/
public native @ByVal Size getTextSize(@Str BytePointer text,
int fontHeight, int thickness,
IntPointer baseLine);
public native @ByVal Size getTextSize(@Str String text,
int fontHeight, int thickness,
IntBuffer baseLine);
public native @ByVal Size getTextSize(@Str BytePointer text,
int fontHeight, int thickness,
int[] baseLine);
public native @ByVal Size getTextSize(@Str String text,
int fontHeight, int thickness,
IntPointer baseLine);
public native @ByVal Size getTextSize(@Str BytePointer text,
int fontHeight, int thickness,
IntBuffer baseLine);
public native @ByVal Size getTextSize(@Str String text,
int fontHeight, int thickness,
int[] baseLine);
}
/** \brief Create FreeType2 Instance
The function createFreeType2 create instance to draw UTF-8 strings.
*/
@Namespace("cv::freetype") public static native @Ptr FreeType2 createFreeType2();
/** \} */
// namespace freetype
// #endif
// #endif
}
编译完成后可以看到最终的 opencv-3.4.2-1.4.3-SNAPSHOT-macosx-x86_64.jar 文件里面多了一个
/org/bytedeco/javacpp/macosx-x86_64/libopencv_freetype.3.4.dylib
按照下面调用API即可
FreeType2 ft2 = opencv_freetype.createFreeType2();
//需要载入一个一种中午的字体 这里是宋体
ft2.loadFontData("src/main/resources/ttf/Songti.ttc", 0);
ft2.setSplitNumber(1);
ft2.putText(mat, //图片
label, //文字
new Point(100,100), //开始的位置
18, //大小 单位是px
Scalar.BLACK, //颜色
1, //thickness 粗细
opencv_core.LINE_4, //线条类型
false); //bottomLeftOrigin=true