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

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

麻雀虽小五脏俱全。

采用的加解码库: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++图像处理的代码示例的更多相关文章

  1. 分享用于学习C++音频处理的代码示例

    与<分享用于学习C++图像处理的代码示例>为姊妹篇. 为了便于学习C++音频处理并研究音频算法, 俺写了一个适合初学者学习的小小框架. 麻雀虽小五脏俱全,仅仅考虑单通道处理. 采用Deco ...

  2. H5+ 分享到微信、朋友圈代码示例

    h5+分享到微信.朋友圈代码示例 在使用分享功能的时候会莫名的分享失败,debug时发现是图片过大的问题. 图片过大时ios平台上返回错误码-8,安卓上返回错误码-3(我测试是这样) 因此如果第一次分 ...

  3. Redis学习记录及Jedis代码示例

    文章目录 二.Redis简介 三.Redis安装 1. 下载并解压安装 2. 安装C语言编译环境 3. 修改安装位置 4. 编译安装 5.启动Redis服务器 ①默认启动 ②定制配置项启动 [1]准备 ...

  4. RabbitMQ基础学习笔记(C#代码示例)

    一.定义: MQ是MessageQueue,消息队列的简称(是流行的开源消息队列系统,利用erlang语言开发).MQ是一种应用程序对应用程序的通信方法.应用程序通过读写入队和出队的消息来通信,无需专 ...

  5. Delphi之通过代码示例学习XML解析、StringReplace的用法(异常控制 good)

    *Delphi之通过代码示例学习XML解析.StringReplace的用法 这个程序可以用于解析任何合法的XML字符串. 首先是看一下程序的运行效果: 以解析这样一个XML的字符串为例: <? ...

  6. Spring 注解学习 详细代码示例

    学习Sping注解,编写示例,最终整理成文章.如有错误,请指出. 该文章主要是针对新手的简单使用示例,讲述如何使用该注释,没有过多的原理解析. 已整理的注解请看右侧目录.写的示例代码也会在结尾附出. ...

  7. OSG学习:阴影代码示例

    效果图: 代码示例: #include <osgViewer/Viewer> #include <osg/Node> #include <osg/Geode> #i ...

  8. 转:CodeCube提供可共享、可运行的代码示例

    CodeCube是一个新服务和开源项目,旨在让开发者能够通过浏览器以一种安全的方式分享并运行代码示例从而提升协作. 最初发布的服务可以从codecube.io上获取,支持Ruby.Python.Go及 ...

  9. 借助全新 MATLAB® 适配器代码示例读取英特尔® 实感™ 摄像头数据流

    下载源代码请访问原文地址:借助全新 MATLAB® 适配器代码示例读取英特尔® 实感™ 摄像头数据流 简介 该可下载代码示例简要介绍了如何使用英特尔® 实感™ SDK 和 MATLAB 的图像采集工具 ...

随机推荐

  1. window下安装redis

    以cmd安装方法: .下载安装包:https://github.com/dmajkic/redis/downloads .安装包下载后根据操作系统选择对应版本文件,里面会有几个dll分别为: redi ...

  2. svn的管理与维护要点—纯手工编写

    由于在公司要维护阿里云的linux服务器,我们的svn服务器就安在阿里云上面.所以经常会涉及到svn的维护操作.离职的时候编写交接文档,刚好有充足的时间写一篇说明介绍,此说明纯原创,不是从网上复制,手 ...

  3. www.97top10.com--做最好的技术交流网站

    www.97top10.com--做最好的技术交流网站

  4. linux线程控制&线程分离

    线程概念 线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元. 线程是程序中一个单一的顺序控制流程.进程内一个相对独立的.可调度的执行单元,是系统独立 ...

  5. 初识HTTP协议

    本篇文章从概念上初识HTTP协议,参考链接:http://www.runoob.com/http/http-tutorial.html 目录: 一.HTTP协议    HTTP 工作原理    HTT ...

  6. [Xamarin.Android] 自定义控件

    [Xamarin.Android] 自定义控件 前言 软件项目开发的过程中,免不了遇到一些无法使用内建控件就能满足的客户需求,例如:时速表.折线图...等等.这时开发人员可以透过自定义控件的方式,为项 ...

  7. [C/C++] VS 2015 C++ 插件

    Visual Studio2015 Community一些必备插件 ReSharper C++ 各种语言版本的代码重构,代码风格,代码修正功能,非常强大,可惜不是免费的,不过好在可以破解呢. Vias ...

  8. android XMl 解析神奇xstream 三: 把复杂对象转换成 xml

    前言:对xstream不理解的请看: android XMl 解析神奇xstream 一: 解析android项目中 asset 文件夹 下的 aa.xml 文件 android XMl 解析神奇xs ...

  9. GitHub 基本常用知识解答

    1.Fork.Watch.Star 是什么意思? fork的意思是从别人的代码库中复制一份到你自己的代码库,与普通的复制不同,fork包含了原有库中的所有提交记录, fork后这个代码库是完全独立的, ...

  10. Android自定义控件之轮播图控件

    背景 最近要做一个轮播图的效果,网上看了几篇文章,基本上都能找到实现,效果还挺不错,但是在写的时候感觉每次都要单独去重新在Activity里写一堆代码.于是自己封装了一下.本篇轮播图实现原理原文出处: ...