分享用于学习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
附带处理耗时计算,示例演示了一个简单的反色处理算法,并简单注释了一下部分逻辑。
完整代码:
#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
若此博文能帮到您,欢迎扫码小额赞助。
微信:

支付宝:

分享用于学习C++图像处理的代码示例的更多相关文章
- 分享用于学习C++音频处理的代码示例
与<分享用于学习C++图像处理的代码示例>为姊妹篇. 为了便于学习C++音频处理并研究音频算法, 俺写了一个适合初学者学习的小小框架. 麻雀虽小五脏俱全,仅仅考虑单通道处理. 采用Deco ...
- H5+ 分享到微信、朋友圈代码示例
h5+分享到微信.朋友圈代码示例 在使用分享功能的时候会莫名的分享失败,debug时发现是图片过大的问题. 图片过大时ios平台上返回错误码-8,安卓上返回错误码-3(我测试是这样) 因此如果第一次分 ...
- Redis学习记录及Jedis代码示例
文章目录 二.Redis简介 三.Redis安装 1. 下载并解压安装 2. 安装C语言编译环境 3. 修改安装位置 4. 编译安装 5.启动Redis服务器 ①默认启动 ②定制配置项启动 [1]准备 ...
- RabbitMQ基础学习笔记(C#代码示例)
一.定义: MQ是MessageQueue,消息队列的简称(是流行的开源消息队列系统,利用erlang语言开发).MQ是一种应用程序对应用程序的通信方法.应用程序通过读写入队和出队的消息来通信,无需专 ...
- Delphi之通过代码示例学习XML解析、StringReplace的用法(异常控制 good)
*Delphi之通过代码示例学习XML解析.StringReplace的用法 这个程序可以用于解析任何合法的XML字符串. 首先是看一下程序的运行效果: 以解析这样一个XML的字符串为例: <? ...
- Spring 注解学习 详细代码示例
学习Sping注解,编写示例,最终整理成文章.如有错误,请指出. 该文章主要是针对新手的简单使用示例,讲述如何使用该注释,没有过多的原理解析. 已整理的注解请看右侧目录.写的示例代码也会在结尾附出. ...
- OSG学习:阴影代码示例
效果图: 代码示例: #include <osgViewer/Viewer> #include <osg/Node> #include <osg/Geode> #i ...
- 转:CodeCube提供可共享、可运行的代码示例
CodeCube是一个新服务和开源项目,旨在让开发者能够通过浏览器以一种安全的方式分享并运行代码示例从而提升协作. 最初发布的服务可以从codecube.io上获取,支持Ruby.Python.Go及 ...
- 借助全新 MATLAB® 适配器代码示例读取英特尔® 实感™ 摄像头数据流
下载源代码请访问原文地址:借助全新 MATLAB® 适配器代码示例读取英特尔® 实感™ 摄像头数据流 简介 该可下载代码示例简要介绍了如何使用英特尔® 实感™ SDK 和 MATLAB 的图像采集工具 ...
随机推荐
- PHP框架中最喜欢的WindFramework
题外话, 像我这样从小到大作文打0分居多的人,写文章,实在是没有耐心的,抱歉. 尽管自己也山寨过许多PHP框架,但被山寨的对象中,最喜欢的是WindFramework. Yii其实更好,但太大而全. ...
- Linux命令详解之–ls命令
今天开始为大家介绍下Linux中常用的命令,首先给大家介绍下Linux中使用频率最高的命令--ls命令. 更多Linux命令详情请看:Linux命令速查手册 linux ls命令用于显示指定工作目录下 ...
- 那一夜,我们..奋笔疾书敲出的--->>库存管理系统
说了会再见,最近好吗?无论你在哪里>也许你在温暖的家,或许你在身在异乡的城市;或许你高高的峰顶放生高歌,或许你还在陡峭的山峰半空努力攀爬.......相信我们都会登上顶峰,"会当凌绝顶 ...
- 前端技巧:禁止浏览器static files缓存篇(转)
前端技巧:禁止浏览器static files缓存篇 由于CSS/JS文件经常需要改动,前端调试时是不希望浏览器缓存这些文件的. 本文记录博主的经验. Meta法 目前在chrome调试还没有遇到问题, ...
- .NET Core应用程序的2种部署方式
1. Portable 共享.NET Core运行时环境与程序集依赖,部署的目标机器上需要事先安装.NET Core SDK,这是.NET Core的默认部署方式. 2. Self-contained ...
- Play Framework介绍:控制器层
业务逻辑代码通常位于模型(model)层.客户端(比如浏览器)无法直接调用其中的代码,所以模型对象提供的功能,必须作为资源以URI方式暴露给外部. 客户端使用HTTP协议来操作这些资源,从而调用了内部 ...
- H5前端面试题及答案(1)
前几天去面试了一家公司,整下改公司的面试题. 1.新的 HTML5 文档类型和字符集是? HTML5 文档类型很简单: <!doctype html> HTML5 使用 UTF-8 编码示 ...
- [模仿][JS]新浪财经7*24直播
使用新浪财经7*24直播的数据 简单的做一个山寨品 在线地址:[痛苦啊,有GFW,却没有vpn,往heroku上传浪费了好多时间...] http://wangxinsheng.herokuapp.c ...
- GitHub上我收藏Java及Android的项目Demo
接触编程不久但浏览频率最高的还是GitHub毕竟它真的是程序员必不可少的新世界. (2016/9/23更新) 静态更新,很强势你值得拥有 更新资源不需要重新安装APK (2016.9.10更新) ht ...
- 移位操作<<和>>,是逻辑数字上的移动(和大端小端无关)
问题描述 这几天帮同事调试DSP TMS320F28335,这鬼东西蛋疼死了.char是16bit的,16位就是他的最小内存单元.但是PC机串口发过来的有8bit的数据,然后转换就出问题. 一开始不知 ...