【分享用于学习C++图像处理的代码示例】框架

转自:分享用于学习C++图像处理的代码示例

为了便于学习图像处理并研究图像算法,

俺写了一个适合初学者学习的小小框架。

 

麻雀虽小五脏俱全。

 

采用的加解码库:stb_image

官方:http://nothings.org/

 

stb_image.h用于解析图片格式:

JPG, PNG, TGA, BMP, PSD, GIF, HDR, PIC

stb_image_write.h用于保存图片格式:

PNG, TGA, BMP, HDR

 

附带处理耗时计算,示例演示了一个简单的反色处理算法,并简单注释了一下部分逻辑。

 

完整代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
#include <iostream>
#include <algorithm>
 
#include <cstdint>
#include <numeric>
#include <math.h>
#include <io.h>
 
//使用stbImage http://nothings.org/
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"
 
//如果是Windows的话,调用系统API ShellExecuteA打开图片
#if defined(_MSC_VER)
#include <windows.h>
#define USE_SHELL_OPEN
#endif
 
//是否使用OMP方式计时
#define USE_OMP 0
 
#if  USE_OMP
#include <omp.h>
auto  const  epoch = omp_get_wtime();
double  now() {
     return  omp_get_wtime() - epoch;
};
#else
#include <chrono>
auto  const  epoch = std::chrono::steady_clock::now();
double  now() {
     return  std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - epoch).count() / 1000.0;
};
#endif
 
//计时函数
template < typename  FN>
double  bench( const  FN &fn) {
     auto  took = -now();
     return  (fn(), took + now());
}
 
//存储当前传入文件位置的变量
std::string m_curFilePath;
 
//加载图片
void  loadImage( const  char * filename, unsigned  char *& Output,  int   &Width,  int   &Height,  int  &Channels)
{
     Output = stbi_load(filename, &Width, &Height, &Channels, 0);
}
//保存图片
void  saveImage( const  char * filename,  int   Width,  int   Height,  int  Channels, unsigned  char * Output,  bool  open =  true )
{
     std::string saveFile = m_curFilePath;
     saveFile += filename;
     //保存为png,也可以调用stbi_write_bmp 保存为bmp
     stbi_write_png(saveFile.c_str(), Width, Height, Channels, Output, 0);
 
#ifdef USE_SHELL_OPEN
     if  (open)
         ShellExecuteA(NULL,  "open" , saveFile.c_str(), NULL, NULL, SW_SHOW);
#else
     //其他平台暂不实现
#endif
}
 
//取当前传入的文件位置
void  getCurrentFilePath( const  char * filePath, std::string& curFilePath)
{
     char  drive[_MAX_DRIVE];
     char  dir[_MAX_DIR];
     char  fname[_MAX_FNAME];
     char  ext[_MAX_EXT];
     curFilePath.clear();
     _splitpath_s(filePath, drive, dir, fname, ext);
     curFilePath += drive;
     curFilePath += dir;
     curFilePath += fname;
     curFilePath +=  "_" ;
}
 
//算法处理,这里以一个反色作为例子
void  processImage(unsigned  char * Input, unsigned  char * Output, unsigned  int   Width, unsigned  int   Height, unsigned  int  Channels)
{
     int  WidthStep = Width*Channels;
     if  (Channels == 1)
     {
         for  (unsigned  int  Y = 0; Y < Height; Y++)
         {
             unsigned  char *     pOutput = Output + (Y * WidthStep);
             unsigned  char *     pInput = Input + (Y * WidthStep);
             for  (unsigned  int  X = 0; X < Width; X++)
             {
                 pOutput[0] = 255 - pInput[0];
 
                 //下一个像素点
                 pInput += Channels;
                 pOutput += Channels;
             }
         }
     }
     else     if  (Channels == 3 || Channels == 4)
     {
         for  (unsigned  int  Y = 0; Y < Height; Y++)
         {
             unsigned  char *     pOutput = Output + (Y * WidthStep);
             unsigned  char *     pInput = Input + (Y * WidthStep);
             for  (unsigned  int  X = 0; X < Width; X++)
             {
                 pOutput[0] = 255 - pInput[0];
                 pOutput[1] = 255 - pInput[1];
                 pOutput[2] = 255 - pInput[2];
                 //通道数为4时,不处理A通道反色(pOutput[3] = 255 - pInput[3];)
                 //下一个像素点
                 pInput += Channels;
                 pOutput += Channels;
             }
         }
     }
 
}
 
//本人博客:http://tntmonks.cnblogs.com/转载请注明出处.
 
int  main( int  argc,  char  **argv) {
 
     std::cout <<  "Image Processing "  << std::endl;
     std::cout <<  "Demo By Gaozhihan (Build 2016-03-22)"  << std::endl;
     std::cout <<  "支持解析如下图片格式:"  << std::endl;
     std::cout <<  "JPG, PNG, TGA, BMP, PSD, GIF, HDR, PIC"  << std::endl;
 
     //检查参数是否正确
     if  (argc < 2)
     {
         std::cout <<  "参数错误。"  << std::endl;
         std::cout <<  "请拖放文件到可执行文件上,或使用命令行:imageProc.exe 图片"  << std::endl;
         std::cout <<  "例如: imageProc.exe d:\\image.jpg"  << std::endl;
 
         return  0;
     }
 
     std::string szfile = argv[1];
     //检查输入的文件是否存在
     if  (_access(szfile.c_str(), 0) == -1)
     {
         std::cout <<  "输入的文件不存在,参数错误!"  << std::endl;
     }
 
     getCurrentFilePath(szfile.c_str(), m_curFilePath);
 
     int  Width = 0;         //图片宽度
     int  Height = 0;         //图片高度
     int  Channels = 0;     //图片通道数
     unsigned  char * inputImage = NULL;     //输入图片指针
 
     double  nLoadTime = bench([&]{
         //加载图片
         loadImage(szfile.c_str(), inputImage, Width, Height, Channels);
     });
     std::cout <<  " 加载耗时: "  <<  int (nLoadTime * 1000) <<  " 毫秒"  << std::endl;
     if  ((Channels != 0) && (Width != 0) && (Height != 0))
     {
         //分配与载入同等内存用于处理后输出结果
         unsigned  char * outputImg = (unsigned  char *)STBI_MALLOC(Width*Channels*Height* sizeof (unsigned  char ));
         if  (inputImage) {
             //如果图片加载成功,则将内容复制给输出内存,方便处理
             memcpy (outputImg, inputImage, Width*Channels*Height);
         }
         else      {
             std::cout <<  " 加载文件: \n"  << szfile.c_str() <<  " 失败!"  << std::endl;
         }
 
         double  nProcessTime = bench([&]{
             //处理算法
             processImage(inputImage, outputImg, Width, Height, Channels);
         });
         std::cout <<  " 处理耗时: "  <<  int (nProcessTime * 1000) <<  " 毫秒"  << std::endl;
 
         //保存处理后的图片
         double  nSaveTime = bench([&]{
             saveImage( "_done.png" , Width, Height, Channels, outputImg);
         });
         std::cout <<  " 保存耗时: "  <<  int (nSaveTime * 1000) <<  " 毫秒"  << std::endl;
 
         //释放占用的内存
         if  (outputImg)
         {
             STBI_FREE(outputImg);
             outputImg = NULL;
         }
 
         if  (inputImage)
         {
             STBI_FREE(inputImage);
             inputImage = NULL;
         }
     }
     else
     {
         std::cout <<  " 加载文件: \n"  << szfile.c_str() <<  " 失败!"  << std::endl;
     }
 
     getchar ();
     std::cout <<  "按任意键退出程序 \n"  << std::endl;
     return  0;
}

  

示例具体流程为:

加载图片->算法处理->保存图片->打开保存图片(仅Windows)

并对 加载,处理,保存 这三个环节都进行了耗时计算并输出。

 

示例代码下载:

http://files.cnblogs.com/files/tntmonks/imageProcDemo.zip

 

若有其他相关问题或者需求也可以邮件联系俺探讨。

邮箱地址是: 
gaozhihan@vip.qq.com

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个使用 TNN 框架和 OpenCV 库实现的 C++ 代码示例用于将输入的图像按照指定的方式进行分割: ```cpp #include <iostream> #include <string> #include <vector> #include <opencv2/opencv.hpp> #include "tnn/core/macro.h" #include "tnn/core/context.h" #include "tnn/device/cpu/cpu_device.h" #include "tnn/interpreter/tnn/tnn_interpreter.h" #include "tnn/utils/mat_utils.h" using namespace std; using namespace cv; using namespace TNN_NS; int main() { // 加载模型和配置文件 TNN_NS::ModelConfig config; config.model_type = TNN_NS::MODEL_TYPE_TNN; config.params.push_back("model.tnnproto"); config.params.push_back("model.tnnmodel"); TNN_NS::TNN_Interpeter interpreter; TNN_NS::Status status = interpreter.Init(config); if (status != TNN_NS::TNN_OK) { std::cerr << "Error: Init TNN Interpreter failed: " << status.description() << endl; return -1; } // 创建 CPU 上下文 TNN_NS::CPUDevice cpu_device; TNN_NS::Context context; context.device_list.push_back(&cpu_device); context.memory_type = TNN_NS::DEVICE_MEMORY_TYPE_AUTO; // 加载输入图像 Mat input_image = imread("input.jpg"); if (input_image.empty()) { std::cerr << "Error: Load input image failed" << endl; return -1; } // 预处理输入图像 Mat input_mat; input_image.convertTo(input_mat, CV_32FC3); cv::cvtColor(input_mat, input_mat, cv::COLOR_BGR2RGB); auto input_dims = interpreter.GetInputShape(0); input_dims[0] = 1; TNN_NS::MatUtils::ConvertCVMatToTNNMat(input_mat, interpreter.GetInputMat(0)); // 运行神经网络 status = interpreter.Interpret(&context); if (status != TNN_NS::TNN_OK) { std::cerr << "Error: Run TNN Interpreter failed: " << status.description() << endl; return -1; } // 获取分割结果 TNN_NS::Mat output_mat; status = interpreter.GetOutputMat(output_mat, 0); if (status != TNN_NS::TNN_OK) { std::cerr << "Error: Get TNN output failed: " << status.description() << endl; return -1; } // 后处理分割结果 auto output_dims = output_mat.GetDims(); int num_classes = output_dims[1]; int height = output_dims[2]; int width = output_dims[3]; vector<Mat> output_images(num_classes); for (int i = 0; i < num_classes; i++) { output_images[i] = Mat(height, width, CV_32FC1, output_mat.GetData() + i * height * width); output_images[i] = output_images[i] * 255; output_images[i].convertTo(output_images[i], CV_8UC1); } // 保存分割结果 for (int i = 0; i < num_classes; i++) { string output_filename = "output_" + to_string(i) + ".jpg"; imwrite(output_filename, output_images[i]); } return 0; } ``` 本代码使用 TNN 框架和 OpenCV 库来实现图像分割。首先,我们加载模型和配置文件,并创建一个 TNN_Interpeter 对象,以便在 CPU 上下文中运行神经网络。然后,我们加载输入图像,并使用 OpenCV 库进行预处理。在预处理过程中,我们将输入图像转换为 TNN 支持的格式,并将其设置为神经网络输入。接下来,我们调用 Interpret() 函数运行神经网络,并使用 GetOutputMat() 函数获取分割结果。最后,我们对分割结果进行后处理,并使用 imwrite() 函数将输出图像保存到文件中。 请注意,本示例仅适用于输入单个图像的情况。如果您需要处理多个图像,请将代码放入循环中,并替换 input_image 和输出路径。同时,请根据您的网络架构和数据集自定义后处理代码

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值