前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >分享用于学习C++图像处理的代码示例

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

作者头像
cpuimage
发布2018-04-12 14:53:01
1.9K0
发布2018-04-12 14:53:01
举报
文章被收录于专栏:算法+算法+

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

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

麻雀虽小五脏俱全。

采用Decoder:stb_image

https://github.com/nothings/stb/blob/master/stb_image.h

采用Encoder:tiny_jpeg https://github.com/serge-rgb/TinyJPEG/blob/master/tiny_jpeg.h

stb_image.h用于解析图片格式:  JPG, PNG, TGA, BMP, PSD, GIF, HDR, PIC

tiny_jpeg.h用于保存JPG格式。

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

完整代码:

代码语言:javascript
复制
//如果是Windows的话,调用系统API ShellExecuteA打开图片
#if defined(_MSC_VER)
#define _CRT_SECURE_NO_WARNINGS
#include <windows.h>
#define USE_SHELL_OPEN
#endif

#define STB_IMAGE_STATIC
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
//ref:https://github.com/nothings/stb/blob/master/stb_image.h
#define TJE_IMPLEMENTATION
#include "tiny_jpeg.h" 
//ref:https://github.com/serge-rgb/TinyJPEG/blob/master/tiny_jpeg.h
#include <math.h>
#include <io.h>
#include <iostream>
#include <string> 
#include <chrono>

//计时 
auto const epoch = std::chrono::steady_clock::now();
static double now()
{
    return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - epoch).count() / 1000.0;
};

template <typename FN>
static 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;
    //保存为jpg
    if (!tje_encode_to_file(saveFile.c_str(), Width, Height, Channels, Output))
    {
        fprintf(stderr, "写入 JPEG 文件失败.\n");
        return;
    }

#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 Stride = Width * Channels;
    if (Channels == 1)
    {
        for (unsigned int Y = 0; Y < Height; Y++)
        {
            unsigned char *scanLineOut = Output + (Y * Stride);
            unsigned char *scanLineIn = Input + (Y * Stride);
            for (unsigned int X = 0; X < Width; X++)
            {
                scanLineOut[0] = 255 - scanLineIn[0];

                scanLineIn++;
                scanLineOut++;
            }
        }
    }
    else if (Channels == 3 || Channels == 4)
    {
        for (unsigned int Y = 0; Y < Height; Y++)
        {
            unsigned char *scanLineOut = Output + (Y * Stride);
            unsigned char *scanLineIn = Input + (Y * Stride);
            for (unsigned int X = 0; X < Width; X++)
            {
                scanLineOut[0] = 255 - scanLineIn[0];
                scanLineOut[1] = 255 - scanLineIn[1];
                scanLineOut[2] = 255 - scanLineIn[2];
                //通道数为4时,不处理A通道反色(scanLineOut[3] =  255- scanLineIn[3];
                scanLineIn += Channels;
                scanLineOut += Channels;
            }
        }
    }
}

int main(int argc, char **argv)
{
    std::cout << "Image Processing " << std::endl;
    std::cout << "博客:http://tntmonks.cnblogs.com/" << 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.jpg", Width, Height, Channels, outputImg);
        });
        std::cout << " 保存耗时: " << int(nSaveTime * 1000) << " 毫秒" << std::endl;

        //释放占用的内存
        if (outputImg)
        {
            stbi_image_free(outputImg);
            outputImg = NULL;
        }

        if (inputImage)
        {
            stbi_image_free(inputImage);
            inputImage = NULL;
        }
    }
    else
    {
        std::cout << " 加载文件: \n"     << szfile.c_str() << " 失败!" << std::endl;
    }

    getchar();
    std::cout << "按任意键退出程序 \n" << std::endl;

    return EXIT_SUCCESS;
}

示例具体流程为:

加载图片(拖放文件到可执行文件上)->算法处理->保存图片->打开保存图片(仅Windows)

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

旧版示例代码下载:

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

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

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

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016-03-22 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
图像处理
图像处理基于腾讯云深度学习等人工智能技术,提供综合性的图像优化处理服务,包括图像质量评估、图像清晰度增强、图像智能裁剪等。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档