[编程开发]STB image读取学习
为了便于学习图像处理并研究图像算法,
俺写了一个适合初学者学习的小小框架。
麻雀虽小五脏俱全。
采用的加解码库: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 << " 加载文件:
" << 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 << " 加载文件:
" << szfile.c_str() << " 失败!" << std::endl;
} getchar();
std::cout << "按任意键退出程序
" << std::endl;
return 0;
}
示例具体流程为:
加载图片->算法处理->保存图片->打开保存图片(仅Windows)
并对 加载,处理,保存 这三个环节都进行了耗时计算并输出。
http://files.cnblogs.com/files/tntmonks/imageProcDemo.zip
[编程开发]STB image读取学习的更多相关文章
- 编程开发之--java多线程学习总结(6)
5.测试 package com.lfy.ThreadsSynchronize; public class Test { public static void main(String[] args) ...
- 编程开发之--java多线程学习总结(5)
4.对继承自Runnable的线程进行锁机制的使用 package com.lfy.ThreadsSynchronize; import java.util.concurrent.locks.Lock ...
- 编程开发之--java多线程学习总结(4)
3.使用锁机制lock,unlock package com.lfy.ThreadsSynchronize; import java.util.concurrent.locks.Lock; impor ...
- 编程开发之--java多线程学习总结(3)类锁
2.使用方法同步 package com.lfy.ThreadsSynchronize; /** * 1.使用同步方法 * 语法:即用 synchronized 关键字修饰方法(注意是在1个对象中用锁 ...
- 编程开发之--java多线程学习总结(2)同步代码块
1.第一种解决办法:同步代码块,关键字synchronized package com.lfy.ThreadsSynchronize; /** * 1.使用同步代码块 * 语法: synchroniz ...
- 编程开发之--java多线程学习总结(1)问题引入与概念叙述
1.经典问题,火车站售票,公共票源箱,多个窗口同时取箱中车票销售 package com.lfy.ThreadsSynchronize; /** * 解决办法分析:即我们不能同时让超过两个以上的线程进 ...
- C++编程开发学习的50条建议(转)
每个从事C++开发的朋友相信都能给后来者一些建议,但是真正为此进行大致总结的很少.本文就给出了网上流传的对C++编程开发学习的50条建议,总结的还是相当不错的,编程学习者(不仅限于C++学习者)如果真 ...
- 【转】50条大牛C++编程开发学习建议
每个从事C++开发的朋友相信都能给后来者一些建议,但是真正为此进行大致总结的很少.本文就给出了网上流传的对C++编程开发学习的50条建议,总结的还是相当不错的,编程学习者(不仅限于C++学习者)如果真 ...
- 50条大牛C++编程开发学习建议
每个从事C++开发的朋友相信都能给后来者一些建议,但是真正为此进行大致总结的很少.本文就给出了网上流传的对C++编程开发学习的50条建议,总结的还是相当不错的,编程学习者(不仅限于C++学习者)如果真 ...
随机推荐
- Python使用pip安装TensorFlow模块
1.首先确保已经安装python,然后用pip来安装matplotlib模块. 2.进入到cmd窗口下,建议执行python -m pip install -U pip setuptools进行升级. ...
- danci5
foss community 自由软体社区 可理解为开源 program 英 ['prəʊɡræm] 美 ['proɡræm] n. 程序:计划:大纲 vt. 用程序指令:为…制订计划:为…安排节目 ...
- 转:MySQL到底能支持多大的数据量?
MySQL到底能支持多大的数据量? MySQL是中小型网站普遍使用的数据库之一,然而,很多人并不清楚MySQL到底能支持多大的数据量,再加上某些国内CMS厂商把数据承载量的责任推给它,导致很多不了解M ...
- Object.create 以原对象为原型创建一个新对象
Object.create = function(o){ var Fun = function(){}; Fun.prototype = o; return new Fun(); } var peo ...
- AOP_原理
什么是AOPAOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善.OOP引入封 ...
- MySQL高级管理
#mysql数据库密码的修改 一.mysql密码的修改与恢复 1.修改密码 mysqladmin -u root -p123 password 456 数据库内修改 method.first: upd ...
- 2020年假期sql excel文件 获取
下载地址: https://files.cnblogs.com/files/shmily3929/2020.zip 说明:sql 不区分节假期和周六周末 excel文件区分节假日和周六周末
- learning java Paths Path
import java.nio.file.Path; import java.nio.file.Paths; public class PathTest { public static void ma ...
- WinDbg常用命令系列---内存数据显示和对应符号显示d*s(dds、dps、dqs)
命令dds, dps, dqs显示给定范围内的内存内容.假定该内存是符号表中的一系列地址.相应的符号也会显示出来. dds [Options] [Range] dqs [Options] [Rang ...
- [USACO12MAR]花盆 二分 单调队列
[USACO12MAR]花盆 二分 单调队列 存在一个长度为\(x\)的区间\([l,r]\),使得区间中最大值与最小值差至少为\(w\),求这个最小的\(x\) \(n\le 100000\),\( ...