2015-12-02 09:35:47 litdaguang 阅读数 2857

OpenCUDA

CUDA(Compute Unified Device Architecture),是显卡厂商NVIDIA推出的运算平台。
随着GPU的发展,CUDA使用人数也越来越多。但关于CUDA的库基本都是不开源的,目前手里有上一个项目遗留下的一套图像处理代码,准备整理整理,一步一步的开源出来。想分享出来和大家一起学习。也希望各位CUDA大牛能够奉献自己的源码。

源码地址:https://github.com/LitLeo/OpenCUDA

1. 因为是项目代码,所以前期不能完全开源,源码也只能发一些简单学习型算法的源码。修改后将考虑全部开源和加一些复杂算法

2. 目前还是求学阶段,有学业和课程压力,能不能一直做下去还是个未知数

2015-12.01 更新 版本v0.1

  1. 初始版本,添加马赛克(Mosaic)算法,内有详细注释;
  2. 目前支持的平台为linux;
  3. Image类只提供.o文件,编译方式见Makefile

2015-12.03 更新 版本v0.2

  1. 版本v0.2,添加二值化(Binarize)算法,内有详细注释;
  2. 目前支持的平台为linux;
  3. Image类只提供.o文件,编译方式见Makefile

2015-12.04 更新 版本v0.3

  1. 版本v0.3,添加并行排序(SortArray),内有详细注释
    功能说明:实现并行排序算法,包括:双调排序,Batcher’s 奇偶合并排序,
    以及 shear 排序。其中,双调排序和 Batcher’s 奇偶合并排序
    的数组长度不能超过一个块内的 shared 内存最大限制(一般为 1024)。
    当数组个数大于 1024 时,可以调用 shear 排序,其最大限制为
    1024×1024 的矩阵。

2015-12.04 更新 版本v1.0

  1. 提供CoordiSet Curve ErrorCode Graph Image Matrix Template基础结构类源码
  2. 新增等基础练手算法(CombineImage Complex DownSampleImage EdgeDetection FillUp Flip FlutterBinarze GaussianElimination ICcircleRadii ImageDiff ImageFilter ImageHide ImageOverlay ImageScaling DownSampleImage ImageToText InnerDigger Julia LearningFilter Mandelbrot Mosaic Tattoo Zoom),算法列表见下表,sample文件夹下的算法不再维护
文件名 算法名 功能说明
CombineImage.h/cu 融合图像(Combine Image) 将若干幅图像融合成一幅图像。要求这些图像的 ROI 子区域的尺寸完全相
Complex. h 复数类(Complex) 实现复数之间的加法、乘法、求模、赋值功能。
DownSampleImage. h 缩小图像(DownSampleImage) 根据给定的缩小倍数 N,将输入图像缩小,将其尺寸从width * height 变成 (width / N) * (height / N)
EdgeDetection.h/cu 边缘检测(EdgeDetection) 实现画出两种颜色的边界
FillUp.h/cu 像素处理(FillUp) 检查一个像素的邻域,若其邻域同时存在 l 像素和 v 像素,当 v 像素的个数大于等于某一值时,将所有的 l 像素置为v 像素。
Flip.h/cu 图像翻转(Flip) 实现图像的水平和竖直翻转。
FlutterBinarze.h/cu 抖动二值化(FlutterBinarze) 用像素点疏密表示像素值大小,对灰度图像进行二值抖动,得到二值图像。
GaussianElimination.h/cu 高斯消元法(GaussianElimination) 通过高斯消元法,求出输入行数与列数相等的方阵的上三角方阵
ICcircleRadii.h/cu 最远距离最小的点与最近距离最大的点(ICcircleRadii) 对一个给定轮廓的坐标集,求其所包围领域内的一点最远距离最小的点-----外接圆的半径最近距离最大的点-----内接圆的半径
ImageDiff.h/cu 图像做差(Difference of two Image) 根据输入的两幅灰度图像,对其相应为位置的像素值做差得到差值图像。
ImageFilter.h/cu 多阈值图像过滤(image filter) 给定一幅图像,根据用户输入的阈值数组,取出每个阈值区间对应的图像,如阈值数组为如[0,50,100,150,200],则该算法输出5幅图像,第一幅保原图像的(0,50)灰度值,其余灰度值设为0,第二幅保留原图像的(50,100)灰度值,以此类推,最后一幅保留原图像的(200,255)灰度值。用户输入阈值时应注意,若您选定的阈值为50,100,150,200,则您输入的阈值数组应为[0,50,100,150,200],前面加0,后面不加255。之所以这么处理,使阈值数组元素个数和输出图像函数个数一致。
ImageHide.h/cu 图像隐藏(ImageHide) 实现二值图隐藏于正常图片中(以数据最低位实现)。
ImageOverlay.h/cu 图像叠加(ImageOverlay) 将 n 幅输入图像叠加到一起,输出图像的灰度值等于所有输入图像对应点灰度值乘以相应权重值并求和。
ImageScaling.h/cu 图像扩缩(ImageScaling) 根据给定扩缩中心和扩缩系数,实现图像的扩大或缩小
DownSampleImage.h/cu 拉伸图像(ImageStretch) 根据给定的长宽拉伸倍数 timesWidth 和 timesHeight,将输入图像拉伸,将其尺寸从 width * height 变成(width * timesWidth) * (height * timesHeight)。
ImageToText.h/cu 图像转文本(ImageToText) 将输入的灰度图像转成制定大小的文本,文本中用一个字符代表特定的灰度级。首先将原图缩放到和文本同样大小,然后按照灰度级对应找到文本,写入字符串中
InnerDigger.h/cu 区域抠心(InnerDigger) 输入灰度图,图像中有一个 ROI 区域,对区域中的每个点作如下判断:如果该点的八领域内或者四领域内所有的点都是白色,则置为 0;否则保留原值。
Julia.h/cu 生成 Julia 集(Julia) 以显示区域 W 内所有的点 (mc, mr) 作为初始迭代值 z = z * z + p 进行times 次迭代,z 的初始值为 mc + mr。迭代完成后比较 z 的模和逃逸半径 radius 的大小,根据比较结果进行着色。
LearningFilter.h/cu 学习型滤波(LearningFilter) 根据设定的阈值,对灰度图像进行二值化处理,得到二值图像。
Mandelbrot.h/cu 生成Mandelbrot集(Mandelbrot) 以显示区域W内所有的点(mc, mr)作为初始迭代值 p = mc + mri 对z = z * z + p 进行 times 次迭代,z 的初始值为 0。迭代完成后比较 z的模和逃逸半径 radius 的大小,根据比较结果进行着色。
Mosaic.h/cu 马赛克(Mosaic) 在给定的图像范围内,将图像编程马赛克的样子(电视上常见的遮挡人脸的效果)。
Tattoo.h/cu 贴图(Tattoo) 输入两幅图像,一幅为前景图,一幅为背景图,输出一幅图像:其中输出图像满足当前景图灰度值与指定透明像素相同时,则输出背景图对应的灰度值否则输出前景图灰度值。
Zoom.h/cu 放大镜定义(Zoom) 定义了放大镜类,将图像进行局部放大处理,根据用户要求的对图像放大的中心点、放大尺寸局部放大图片。

The Tesla K40 used for this research was donated by the NVIDIA Corporation.


在这里插入图片描述

2010-02-24 20:30:00 xbt746 阅读数 910

由intel赞助开发,使用起来比较方便,效果不错,有很多成熟算法。也有在上面开发的很多开源算法

图像处理要求很深的数学功底,暂时没用,先记之。

2018-05-02 22:31:27 fanyun_01 阅读数 17525

      1.OpenCV,主要以算法形式,展示其实现;也就是说,它实际提供的是各种图像处理算法。若需具体应用,需要组合其算法以实现某个功能。

                                          

OpenCV 的全称 Open Source Computer Vision Library,是一个基于BSD许可(开源)发行的跨平台计算机视觉库,又名 “开源计算机视觉库”。OpenCV 是一个开源发行的跨平台计算机视觉库,可运行在 Windows、Android、Maemo、FreeBSD、OpenBSD、iOS、Linux 和 Mac OS 等平台。使用者可在 SourceForge 获得官方版本, 或从 SVN 获得开发版本。OpenCV 也用 CMake。

在 Windows 上编译 OpenCV 中与摄像输入有关部分时,需要 DirectShow SDK 中的一些基类。该 SDK 可从预先编译的 Microsoft Platform SDK (or DirectX SDK 8.0 to 9.0c / DirectX Media SDK prior to 6.0) 的子目录 Samples\Multimedia\DirectShow\BaseClasses 获得。

OpenCV 轻量且高效 —— 由一系列 C 函数和少量 C++ 类构成,同时提供了 Python、Ruby、MATLAB 等语言接口,实现了图像处理和计算机视觉方面的很多通用算法。

OpenCV 用 C++ 语言编写,它的主要接口也是 C++ 语言,但依然保留了大量的 C 语言接口。OpenCV 库也有 Python、Java、MATLAB/OCTAVE (版本 2.5) 接口。这些语言的 API 接口函数,可通过在线文档获得。如今,OpenCV 也提供对于 C#、Ch、Ruby 的支持。

OpenCV 所有新开发和算法都采用 C++ 接口。

OpenCV 拥有包括 500 多个 C 函数的跨平台中、高层 API。OpenCV 不依赖于其它的外部库 —— 尽管也可使用某些外部库。

1999 年 Intel 开始建立 OpenCV,如今由 Willow Garage 提供支持。

OpenCV 为 Intel ® Integrated Performance Primitives (IPP) 提供了透明接口。这意味着,如果有为特定处理器优化的 IPP 库, OpenCV 将在运行时自动加载这些库。OpenCV 2.0 版代码已显著优化,无需 IPP 来提升性能,故 2.0 版不再提供 IPP 接口。

2010 年 9 月实现 CUDA 的 GPU 接口。

2015 年 6 月 4 日发布 OpenCV 3.0。

2016年12月,发布OpenCV 3.2版(合并969个修补程序,关闭478个问题)。

2017年8月3日,发布OpenCV 3.3版(最重要的更新是把DNN模块从contrib里面提到主仓库)。

2017年12月23日发布,最新版本是3.4 。

       2.imageMagic主要以应用形式,展示其实现,;譬如:图像切割、图像融合、图像模糊、图像锐化等。

                                           

ImageMagick 是一个免费开源、用于编辑、创建、合成图像的工具。ImageMagick 可读取、转换、写入多种格式图像。包括:图像切割、颜色替换、各种效果的应用,图像旋转、组合、文本、直线、多边形、椭圆、曲线、附加到图像伸展旋转、等等。

ImageMagick 遵守 GPL 许可协议,是一个免费工具:完全开放源码,可自由使用、复制、修改、发布;它可运行于大多数操作系统。ImageMagick 几乎可在任何非专有操作系统上编译,无论是 32 位还是 64 位 CPU,包括:Linux、Windows 95/98/ME/NT 4.0/2000/XP、Windows 2003、Windows 7、Windows 8、Macintosh (MacOS 9 /10)、VMS 和 OS/2。ImageMagick 的大多数功能的用法都是使用命令行。

ImageMagick 是一套功能强大、稳定且开源的工具集、开发包。可用来读、写和处理超过 200 多种格式的图片文件,包括流行的 TIF、JPG、JPEG、GIF、 PNG、PDF 以及 PhotoCD 等格式。

ImageMagick 可根据 Web 应用程序的需要动态生成图片, 可对一个(或一组)图片进行缩放、旋转、锐化、减色或增加特效等操作,并将操作结果以相同格式或其它格式保存;对图片的操作,即可通过命令行进行,也可通过 C/C++、Perl、Java、PHP、Python 或 Ruby 编程完成。同时 ImageMagick 还提供了一个高质量的 2D 工具包,部分支持 SVG。ImageMagick 的主要精力集中在性能,减少 Bug 以及提供稳定的 API 和 ABI 上。

                                 

       3.GraphicsMagick号称图像处理领域的瑞士军刀。其短小精悍的代码却提供了一个鲁棒、高效的工具和库集合,来处理图像的读取、写入和操作。

                                            

GraphicsMagick 号称图像处理领域的瑞士军刀。GraphicsMagick 短小精悍的代码,却提供了一个鲁棒、高效的工具和库集合,来处理图像的读取、写入和操作。

GraphicsMagick 支持大图片的处理,且做过 GB 级的图像处理实验。GraphicsMagick 能动态生成图片,特别适于互联网应用。

GaphicsMagick 不仅支持命令行模式,同时也支持 C、C++、Perl、PHP、Tcl、 Ruby、Lua、Python、Windows .NET、Windows COM 编程接口等的调用。事实上,GraphicsMagick 是从 ImageMagick 5.5.2 分支出来的,现在它已变得更稳定和更优秀,相比之下。

GraphicsMagick 可用来处理调整图片尺寸、旋转、加亮、颜色调整、增加特效等。GraphicsMagick 支持超过 88 种图像格式,包括重要的 DPX、GIF、JPEG、JPEG-2000、PNG、PDF、PNM 和 TIFF。通过使用 OpenMP 可利用多线程进行图片处理,增强了通过扩展 CPU 提高处理能力。

GraphicsMagick 可在绝大多数平台上使用,包括 Linux、Mac OS、Windows (2000、XP、Vista、7、8.X、10) 操作系统。

三种库的优势对比:

OpenCV 比较 ImageMagick:

(1).OpenCV 和 ImageMagick 代码都开源,方便开发;

(2).ImageMagick 最近更新不多,OpenCV 近几年有 Intel 的支持更新比较及时,功能越来越强大,bug 修复也比较及时;

(3).ImageMagick 使用简便;OpenCV 的使用稍微复杂,对使用者有一定的图像技术要求;

(4).ImageMagick 封装较好,使用灵活度稍低;OpenCV 使用比较灵活;

(5).ImageMagick 功能实现较少,主要是一些常用的图像处理,很多比较复杂的图像处理并没有实现。OpenCV 的算法实现非常强大,且从其最近版本更新的速度来看,它更加强大,很多经典的图像处理算法都有实现。作为一个图像开发者,这是一个很大的诱惑。

(6).ImageMagick 函数运行较慢, OpenCV 运行速度较快。常见函数 ,包括:图像读、图像压缩、图像写等 ,OpenCV 都要比 ImageMagick 快很多。

(7).OpenCV 不能解析 gif 文件格式,版权原因,试图载入 gif 文件会出错。若要用 OpenCV 功能,又需解析 gif 文件格式,可先用其他函数库将其读入再转化为 IplImage。ImageMagick 支持处理 gif 文件格式。

(8).ImageMagick 有一个不错的 sharpen 函数,用于锐化图像,效果挺不错。OpenCV 中没有锐化函数,没有相应的锐化算法实现。若确想使用这个函数,可在 OpenCV 下实现 ImageMagick 相应源代码。

OpenCV 功能强大,代码运行速度快,更新速度也快,但对开发者有一定的要求。ImageMagick 使用比较简单,对图像处理不太熟悉,又只想实现简单图像处理时,可选择。

若选择使用 ImageMagick,建议使用 GraphicsMagick。GraphicsMagick 和 ImageMagick 的函数调用方法相同,但 GraphicsMagick 在效率上优于 ImageMagick,特别是在 windows 下运行。

GraphicsMagick 比较 ImageMagick:

(1).GraphicsMagick 更有效率,能更快的完成处理工作;

(2).GraphicsMagick 更小更容易安装;

(3).GraphicsMagick 已被 Flickr (雅虎旗下图片分享网站) 和 Etsy (网络商店平台) 使用,每天处理百万计的图片;

(4).GraphicsMagick 和已安装软件不会发生冲突;

(5).GraphicsMagick 几乎没有安全问题;

(6).GraphicsMagick 的手册非常丰富;





2016-08-02 19:33:14 x454045816 阅读数 10371
图像处理库综述
当需要做一些图像处理方面的学习和研究的时候,首要任务就是选择一套合适的图像处理类库,本文主要简单介绍下各家图像库的一些优缺点。OpenCV,Intel IPP,Halcon,MATLAB ,OpenGL,EmguCv,AForge.net,CxImage,FreeImage,paintlib,AGG,IPL,visDSK。不足之处,还请大家多多提建议,多谢!欢迎微信关注公众号“智能算法”,带您体验不一样的人生!
1. OpenCV
简介:OpenCV全称是:Open Source Computer Vision Library。是Intel®开源计算机视觉库。它由一系列 C 函数和少量 C++ 类构成,实现了图像处理和计算机视觉方面的很多通用算法。OpenCV是一个基于(开源)发行的跨平台计算机视觉库,可以运行在Linux、Windows和Mac OS操作系统上。它轻量级而且高效——由一系列 C 函数和一些C++ 类构成,同时提供了Python、Ruby、MATLAB等语言的接口,实现了图像处理和计算机视觉方面的很多通用算法。OpenCV用C++语言编写,它的主要接口也是C++语言,但是依然保留了大量的C语言接口。
OpenCV功能
提供对图像数据操作,图像/视频的输入输出,基本图像处理,结构分析,摄像头定标,运动分析,目标识别以及基本的GUI等的函数接口。
OpenCV模块
cv – 核心函数库;cvaux – 辅助函数库;cxcore – 数据结构与线性代数库;highgui – GUI函数库;ml – 机器学习函数库
特点:
免费,源代码公开,是一个跨平台的中、高层API 构成,它不依赖与其它的外部库,尽管也可以使用某些外部库。,为了完全独立于IPL (INTEL的图像处理库) OpenCV 复制了IplImage 和其它一些结构变量的声明。
OpenCV 为Intel® Integrated PerformancePrimitives (IPP) 提供了透明的用户使用接口。它对IPP不存在任何依赖。但如果安装了IPP,那么OpenCV将会通过自动载入IPP动态链接库来获取IPP的优势,来提升速度。

2. Intel IPP
简介:IPP“Intel Integrated Performance Primitives” ( Intel IPP )是一套跨平台的软件函数库,
他提供了广泛的多媒体功能:音频解码器(例如: H263 、 MPEG-4 )、图像处理 (JPEG) 、信号处理、语音压缩(例如: G723 、 GSM 、 AMR )和加密机制。
Intel IPP 针对大量的 Intel Microprocessor (微处理器)进行优化: Intel Pentium 4 处理器,采用 Intel Centrino 移动运算技术的 Intel Pentium M 处理器组件, Intel Itanium 2 处理器、 Intel Xeon 处理器以及采用 Intel XScale 技术的 Intel PCA 应用处理器。采用一套跨平台结构的通用 API ,使用者除了不需要担心平台兼容性的问题,更节省了开发成本以及研发时间,使用者可以轻轻松松移植原有应用程序。
特点:
IPP收费源代码不公开,跨平台和OS的通用 API
函数库:信号处理,图像处理,多媒体,向量处理等
高性能代码,不需要写汇编代码,获得优化的应用程序,速度快,效率高

3. Halcon
简介:德国MVtec公司的图像处理软件HALCON,是世界公认具有最佳效能的机器视觉软件。它发源自学术界,有别于市面一些商用软件包。事实上,这是一套图像处理库,由一千多个各自独立的函数,以及底层的数据管理核心构成。其中包含了各类滤波、色彩分析以及几何、数学变换、形态学计算分析、校正、分类、辨识、形状搜索等等基本的几何以及图像计算功能,由于这些功能大多并非针对特定工作设计的,因此只要用得到图像处理的地方,就可以用HALCON强大的计算分析能力来完成工作。应用范围几乎没有限制,涵盖医学、遥感探测、监拎、及工业上的各类自动化检测。近年来,由于机器视觉技术的发展,这种可以”取代人眼”,对重复工作不会疲劳,精度高且稳定的特质,促进了高科技业的发展,例如电子业产量的大幅提升。而MVTec公司更是不断的与学术界合作,并且将最新的学术研究成果纳入其中,不但使自己的技术处于业界领导地位,同时也将机器视觉技术推向更高的境界。
机器视觉软件HALCON在世界范围内被广泛的使用,用户可以利用其开放式结构快速开发图像处理和机器视觉应用。
一个专业的图像处理工具不只包含一个图像处理函数库。图像处理任务的解决只是整个机器视觉解决方案的一部分,还包括处理控件和或者数据库连接等软件部分,图像获取及其照明等硬件部分。因此,图像处理系统简单易用,并且能活嵌入到开发项目中是非常重要的。Halcon充分考虑到这些方面,它有如下的特点:
1). HALCON包含了一套交互式的程序设计接口HDevelop,可在其中以HALCON程序代码直接编写、修改、执行程序,并且可以查看计算过程中的所有变量,设计完成后,可以直接输出C/ C++,或是COM(visual basic)程序代码,嵌入到应用程序程序中。
2). HALCON不限制取像设备,可以自行挑选合适的设备。原厂己提供了4 0余种相机的驱动,即使是尚未支持的相机,除了可以透过指针(pointer)轻易的抓取影像,还可以利用HALOCN开放性的架构,自行编写DLL文件和系统连接。
3). 使用HALCON有最好的投资效益。这套软件支持的操作系统除了微软的NT/XP/2000,还有Linux, Solaris7,  181X6. 5, "1'ru64 UN1X5. 1等等,当需要开发出一套系统,就可以轻易转换作业平台,以符合需求。为了加快速度,还可以使用多处理器的计算机,所编写的程序不必更动。
4). 使用HALOCN,在设计人机接口时没有特别的限制,也不需要特别的可视化组件,可以完全使用开发环境下的程序语言,例如Mircosoft Visual Studio等等,架构自己的接口,最终用户看不到开发工具,而且在执行软件的机器上,只需要很少的资源。

4. MATLAB 
简介:MATLAB 是美国MathWorks公司出品的商业数学软件,用于算法开发、数据可视化、数据分析以及数值计算的高级技术计算语言和交互式环境,主要包括MATLAB和Simulink两大部分。
MATLAB可以进行矩阵运算、绘制函数和数据、实现算法、创建用户界面、连接其他编程语言的程序等,主要应用于工程计算、控制设计、信号处理与通讯、图像处理、信号检测、金融建模设计与分析等领域。
MATLAB的基本数据单位是矩阵,它的指令表达式与数学、工程中常用的形式十分相似,故用MATLAB来解算问题要比用C,FORTRAN等语言完成相同的事情简捷得多,并且MATLAB也吸收了像Maple等软件的优点,使MATLAB成为一个强大的数学软件。在新的版本中也加入了对C, FORTRAN, C++, JAVA的支持。
特点:
1). 高效的数值计算及符号计算功能,能使用户从繁杂的数学运算分析中解脱出来;
2). 具有完备的图形处理功能,实现计算结果和编程的可视化;
3). 友好的用户界面及接近数学表达式的自然化语言,使学者易于学习和掌握;
4). 功能丰富的应用工具箱(如信号处理工具箱、通信工具箱等) ,为用户提供了大量方便实用的处理工具。
功能十分强大,正版软件价钱昂贵,适用于学术研究,仿真和演示。在软件开发,工程应用方面有一定的局限性。

5. OpenGL
OpenGL(全写Open Graphics Library)是指定义了一个跨编程语言、跨平台的编程接口规格的专业的图形程序接口。它用于三维图像(二维的亦可),是一个功能强大,调用方便的底层图形库。
OpenGL 是行业领域中最为广泛接纳的 2D/3D 图形API,其自诞生至今已催生了各种计算机平台及设备上的数千优秀应用程序。OpenGL™ 是独立于视窗操作系统或其它操作系统的,亦是网络透明的。在包含CAD、内容创作、能源、娱乐、游戏开发、制造业、制药业及虚拟现实等行业领域中,OpenGL™ 帮助程序员实现在 PC、工作站、超级计算机等硬件设备上的高性能、极具冲击力的高视觉表现力图形处理软件的开发。
特点:
1). 与C语言紧密结合。
OpenGL命令最初就是用C语言函数来进行描述的,对于学习过C语言的人来讲,OpenGL是容易理解和学习的。如果你曾经接触过TC的graphics.h,你会发现,使用OpenGL作图甚至比TC更加简单。
2). 强大的可移植性。
微软的Direct3D虽然也是十分优秀的图形API,但它只用于Windows系统(现在还要加上一个XBOX游戏机)。而OpenGL不仅用于 Windows,还可以用于Unix/Linux等其它系统,它甚至在大型计算机、各种专业计算机(如:医疗用显示设备)上都有应用。并且,OpenGL 的基本命令都做到了硬件无关,甚至是平台无关。
3). 高性能的图形渲染。
OpenGL是一个工业标准,它的技术紧跟时代,现今各个显卡厂家无一不对OpenGL提供强力支持,激烈的竞争中使得OpenGL性能一直领先。
总之,OpenGL是一个很NB的图形软件接口。至于究竟有多NB,去看看DOOM3和QUAKE4等专业游戏就知道了。

6. EmguCv
EmguCV 是.NET 平台下对OpenCV 图像处理库的封装。也就是OpenCV的.NET 版。它运行在.NET 兼容的编程语言下调用OpenCV 的函数,如C#、VB、VC++、IronPython 等。这个封装库可以在Mono 下编译和在Linux / Mac OSX 上运行。EmguCV 全部用 C#编写 ,它可以在Mono环境里编 译,在 任何 Mono支持的平台 (如 Linux, Solaris,MacOSX ) 上 运 行 。EmguCV 的其他优势还有,支持通用颜色和深度的图像类,自动垃圾收集,可XML序列化的图像,XML 文档和 Intel license 支持, 自由选择图像类或 OpenCV 的 direct invoke 函数 ,图像象 素上的通用操作等。 也就是说 ,EmguCV 不仅继承了 OpenCV 的所有功能和特点 ,而且在跨平台支持方面也有更大的突破 。
将OpenCv的绝大部分功能都包装成了.net类、结构或者枚举。不过文档不全,还是得对照OpenCv的文档去看才行。

7. AForge.net
AForge.NET 是一个专门为开发者和研究者基于C#框架设计的,他包括计算机视觉与人工智能,图像处理,神经网络,遗传算法,机器学习,机器人等领域。
这个框架由一系列的类库和例子组成。其中包括的特征有:
AForge.Imaging -一些日常的图像处理和过滤器
AForge.Vision -计算机视觉应用类库
AForge.Neuro -神经网络计算库
AForge.Genetic -进化算法编程库
AForge.MachineLearning -机器学习类库
AForge.Robotics -提供一些机器学习的工具类库
AForge.Video -一系列的视频处理类库(很方便)
纯.net类库,接口简单,用起来很方便。

8. CxImage
CxImage类库是一个优秀的图像操作类库。它可以快捷地存取、显示、转换各种图像。有的读者可能说,有那么多优秀的图形库,如OpenIL,FreeImage,PaintLib等等,它们可谓是功能强大,齐全,没必要用其它的类库。但我要说,这些类库基本上没有免费的,使用这些类库,你要被这样那样的许可协议所束缚。在这点上,CxImage类库是完全免费的。另外,在使用上述类库时,你会遇到重重麻烦。因为它们大部分是平台无关的,且用C语言写成,有的还夹杂着基本的C++ wrapper和成堆的编译选项的声明需要你去处理。而CxImage类库在这方面做得很好。作者完全公开了源代码。相对于那些封装好的图形库和GDI+来说,这一点使我们可以进一步学习各种编解码技术,而不再浮于各种技术的表面。

9. FreeImage
FreeImage 是一款免费的、开源的、跨平台(Windows 、Linux 和Mac OS X )的,支持20 多种图像类型的(如BMP 、JPEG 、GIF 、PNG 、TIFF 等)图像处理库。其最大优点就是采用插件驱动型架构,具有快速、灵活、简单易用的特点,得到了广泛使用。
FreeImage 的主要功能有多格式位图的读写;方便的位图信息获取;位深度转换;位图页面访问;基本的几何变换和点处理;通道合并与混合等。FreeImage 暂时不支持矢量图形和高级图像处理,位图绘制需要由用户来完成。
FreeImage 中的所有函数都以FreeImage_ 开头,如图像文件的读写函数分别为FreeImage_Load 和FreeImage_Save 。FIBITMAP 数据结构保存着位图信息和像素数据,是FreeImage 的核心。

10. paintlib
paintlib是一个可移植的用于图像加载、保存和处理的C++类库。可从BMP, GIF, JPEG, PCX, PGM, PICT, PNG, PSD, TGA, TIFF和WMF文件中加载图像,且可保存为BMP, JPEG, PNG和TIFF格式。既可通过在过滤器类中执行过滤, 也可通过直接访问位图来进行图像处理。提供了完整的C++源码。

11. AGG
AGG,全名:Anti-Grain Geometry,是一个开源的、高效的2D图形库
AGG是一个高效的、高质量的、开源的矢量图形库,类似的有:GTK+的Cairo,Microsoft的GDI+。在三者中,AGG的性能是最高的(不讨论Skia和Direct2D,他们有OGL和DX的硬件加速,绘图速度根本不是一个档次的)。
特点:
AGG的功能与GDI+的功能非常类似,但提供了比GDI+更灵活的编程接口,其产生的图形的质量也非常高,而且它是跨平台的,其宣传可以在非常多的操作系统上运行.
AGG的功能
1). 支持ALPHA、GAMMA等变色处理,以及用户自定义的变色处理;
2). 支持任意2D图形变换;
3). 支持SVG和PostScript描述,适于网上图形生成;
4). 支持高质量的图形处理,支持反走样插值等高级功能;
5). 支持任意方式的惭变色处理;
6). 支持所有颜色格式;
7). 支持对位图的多种处理;
8). 支持直线的多种处理,类似于GDI+;
9). 支持GPC,即通用多边形裁剪方法;
10). 支持多种字体输出,包括汉字的处理;
效率高,质量高(有反锯齿),功能强大,跨平台和平台GUI支持,缺点:没有硬件加速,文档少,门槛略高.

12. IPL:
Intel 的IPL image library虽然没有开源但是进行普通的图像处理非常好用,像拉布拉斯算子,索贝尔算子等等边缘提取和锐化的函数。 如果目标平台是PC机或者工控机又是Intel的CPU,这是一个非常不错的选择。
现在已经没有IPL了,IPL已经是IPP的一部分了,不过还是可以下载早期版本。IPP的教育版50$,不是很贵,集成大部分算法1D signal processing, 语音信号处理;2D signal prodessing, image processing, video processing. Open CV的模式将很类似于IPL.
特点:
IPL 图象处理库,免费,起初开源,后来不开源。

13. visDSK:
MICROSOFT图像处理库,免费、开源。OpenCV未出现时很受追捧,但是现在visDSK能做的OpenCV都可以做,在速度上,OpenCV还有Intel公司的优化支持。visDSK的时代已然成为过去。

欢迎关注微信公众号“智能算法”,带您体验不一样的人生!

2018-01-31 21:19:55 bjbz_cxy 阅读数 388

这一系列的文章都将以BMP格式图像为主做处理,主要是为了让大家能对图像处理有一个良好的认知,后面会教大家写一个能支持BMP,JPG,JPEG,PNG等格式的图像处理库。

首先你要对图像处理以及图像理论有一个基本的认识,如果没有任何基本的图像知识的话我建议先看一下博主的这篇文章:Opencv学习笔记_计算机视觉是什么?Opencv的起源 虽然说这篇文章是介绍计算机视觉和opencv的但是其中包含了很多图像理论知识。

首先第一步要对BMP图像文件格式要有一个基本的认识:

BMP图像格式详解

一.简介
BMP(Bitmap-File)图形文件是Windows采用的图形文件格式,在Windows环境下运行的所有图象处理软件都支持BMP图象文件格式。Windows系统内部各图像绘制操作都是以BMP为基础的。Windows 3.0以前的BMP图文件格式与显示设备有关,因此把这种BMP图象文件格式称为设备相关位图DDB(device-dependent bitmap)文件格式。Windows 3.0以后的BMP图象文件与显示设备无关,因此把这种BMP图象文件格式称为设备无关位图DIB(device-independent bitmap)格式(注:Windows 3.0以后,在系统中仍然存在DDB位图,象BitBlt()这种函数就是基于DDB位图的,只不过如果你想将图像以BMP格式保存到磁盘文件中时,微软极力推荐你以DIB格式保存),目的是为了让Windows能够在任何类型的显示设备上显示所存储的图象。BMP位图文件默认的文件扩展名是BMP或者bmp(有时它也会以.DIB或.RLE作扩展名)。
 
二.BMP格式结构
BMP文件的数据按照从文件头开始的先后顺序分为四个部分:
◆ 位图文件头(bmp file header):  提供文件的格式、大小等信息
◆ 位图信息头(bitmap information):提供图像数据的尺寸、位平面数、压缩方式、颜色索引等信息
◆ 调色板(color palette):可选,如使用索引来表示图像,调色板就是索引与其对应的颜色的映射表
◆ 位图数据(bitmap data):图像数据区
 
BMP图片文件数据表如下:

 

数据段名称大小(byte)开始地址结束地址
位图文件头(bitmap-file header)
140000h000Dh
位图信息头(bitmap-information header)
40000Eh0035h
调色板(color table)
由biBitCount决定0036h未知
图片点阵数据(bitmap data)
由图片大小和颜色定未知未知

 

 
 
 
三.BMP文件头
BMP文件头结构体定义如下:
typedef struct tagBITMAPFILEHEADER
UINT16 bfType;        //2Bytes,必须为"BM",即0x424D 才是Windows位图文件
DWORD bfSize;         //4Bytes,整个BMP文件的大小
UINT16 bfReserved1;  //2Bytes,保留,为0
UINT16 bfReserved2;  //2Bytes,保留,为0
DWORD bfOffBits;     //4Bytes,文件起始位置到图像像素数据的字节偏移量
BITMAPFILEHEADER;
 
BMP文件头数据表如下:

 

变量名地址偏移大小作用说明
bfType0000h2Bytes
文件标识符,必须为"BM",即0x424D 才是Windows位图文件
‘BM’:Windows 3.1x, 95, NT,…  ‘BA’:OS/2 Bitmap Array  ‘CI’:OS/2 Color Icon   
‘CP’:OS/2 Color Pointer   ‘IC’:OS/2 Icon   
‘PT’:OS/2 Pointer
因为OS/2系统并没有被普及开,所以在编程时,你只需判断第一个标识“BM”就行
bfSize0002h4Bytes整个BMP文件的大小(以位B为单位)
bfReserved10006h2Bytes保留,必须设置为0
bfReserved20008h2Bytes保留,必须设置为0
bfOffBits000Ah4Bytes说明从文件头0000h开始到图像像素数据的字节偏移量(以字节Bytes为单位),以为位图的调色板长度根据位图格式不同而变化,可以用这个偏移量快速从文件中读取图像数据

 

 
 
四.BMP信息头
BMP信息头结构体定义如下:
typedef struct _tagBMP_INFOHEADER
{
DWORD  biSize;    //4Bytes,INFOHEADER结构体大小,存在其他版本I NFOHEADER,用作区分
LONG   biWidth;    //4Bytes,图像宽度(以像素为单位)
LONG   biHeight;    //4Bytes,图像高度,+:图像存储顺序为Bottom2Top,-:Top2Bottom
WORD   biPlanes;    //2Bytes,图像数据平面,BMP存储RGB数据,因此总为1
WORD   biBitCount;         //2Bytes,图像像素位数
DWORD  biCompression;     //4Bytes,0:不压缩,1:RLE8,2:RLE4
DWORD  biSizeImage;       //4Bytes,4字节对齐的图像数据大小
LONG   biXPelsPerMeter;   //4 Bytes,用象素/米表示的水平分辨率
LONG   biYPelsPerMeter;   //4 Bytes,用象素/米表示的垂直分辨率
DWORD  biClrUsed;          //4 Bytes,实际使用的调色板索引数,0:使用所有的调色板索引
DWORD biClrImportant;     //4 Bytes,重要的调色板索引数,0:所有的调色板索引都重要
}BMP_INFOHEADER;
 
BMP信息头数据表如下:

 

变量名
地址偏移
大小
作用说明
biSize
000Eh
4Bytes
BNP信息头即BMP_INFOHEADER结构体所需要的字节数(以字节为单位)
biWidth
0012h
4Bytes
说明图像的宽度(以像素为单位)
biHeight
0016h
4Bytes
说明图像的高度(以像素为单位)。这个值还有一个用处,指明图像是正向的位图还是倒向的位图,该值是正数说明图像是倒向的即图像存储是由下到上;该值是负数说明图像是倒向的即图像存储是由上到下。大多数BMP位图是倒向的位图,所以此值是正值。
biPlanes
001Ah
2Bytes
为目标设备说明位面数,其值总设置为1
biBitCount
001Ch
2Bytes
说明一个像素点占几位(以比特位/像素位单位),其值可为1,4,8,16,24或32
biCompression
001Eh
4Bytes
说明图像数据的压缩类型,取值范围为:
0         BI_RGB 不压缩(最常用)
1         BI_RLE8 8比特游程编码(BLE),只用于8位位图
2         BI_RLE4 4比特游程编码(BLE),只用于4位位图
3         BI_BITFIELDS比特域(BLE),只用于16/32位位图
4          
biSizeImage
0022h
4Bytes
说明图像的大小,以字节为单位。当用BI_RGB格式时,总设置为0
biXPelsPerMeter
0026h
4Bytes
说明水平分辨率,用像素/米表示,有符号整数
biYPelsPerMeter
002Ah
4Bytes
说明垂直分辨率,用像素/米表示,有符号整数
biClrUsed002Eh4Bytes说明位图实际使用的调色板索引数,0:使用所有的调色板索引
biClrImportant0032h4Bytes说明对图像显示有重要影响的颜色索引的数目,如果是0,表示都重要。

 

 
五.BMP调色板
BMP调色板结构体定义如下:
typedef struct _tagRGBQUAD
{
BYTE  rgbBlue;       //指定蓝色强度
BYTE  rgbGreen;      //指定绿色强度
BYTE  rgbRed;        //指定红色强度
 BYTE  rgbReserved;  //保留,设置为0
RGBQUAD;
 
1,4,8位图像才会使用调色板数据,16,24,32位图像不需要调色板数据,即调色板最多只需要256项(索引0 - 255)。
颜色表的大小根据所使用的颜色模式而定:2色图像为8字节;16色图像位64字节;256色图像为1024字节。其中,每4字节表示一种颜色,并以B(蓝色)、G(绿色)、R(红色)、alpha(32位位图的透明度值,一般不需要)。即首先4字节表示颜色号1的颜色,接下来表示颜色号2的颜色,依此类推。
颜色表中RGBQUAD结构数据的个数有biBitCount来确定,当biBitCount=1,4,8时,分别有2,16,256个表项。
当biBitCount=1时,为2色图像,BMP位图中有2个数据结构RGBQUAD,一个调色板占用4字节数据,所以2色图像的调色板长度为2*4为8字节。
当biBitCount=4时,为16色图像,BMP位图中有16个数据结构RGBQUAD,一个调色板占用4字节数据,所以16像的调色板长度为16*4为64字节。
当biBitCount=8时,为256色图像,BMP位图中有256个数据结构RGBQUAD,一个调色板占用4字节数据,所以256色图像的调色板长度为256*4为1024字节。
当biBitCount=16,24或32时,没有颜色表。
 
五.BMP图像数据区
位图数据记录了位图的每一个像素值,记录顺序是在扫描行内是从左到右,扫描行之间是从下到上。位图的一个像素值所占的字节数:
当biBitCount=1时,8个像素占1个字节;
当biBitCount=4时,2个像素占1个字节;
当biBitCount=8时,1个像素占1个字节;
当biBitCount=24时,1个像素占3个字节;
Windows规定一个扫描行所占的字节数必须是4的倍数(即以long为单位),不足的以0填充,
一个扫描行所占的字节数计算方法:
DataSizePerLine= (biWidth* biBitCount+31)/8;
// 一个扫描行所占的字节数
DataSizePerLine= DataSizePerLine/4*4; // 字节数必须是4的倍数
位图数据的大小(不压缩情况下):
DataSize= DataSizePerLine* biHeight;
 
颜色表接下来位为位图文件的图像数据区,在此部分记录着每点像素对应的颜色号,其记录方式也随颜色模式而定,既2色图像每点占1位(8位为1字节);16色图像每点占4位(半字节);256色图像每点占8位(1字节);真彩色图像每点占24位(3字节)。所以,整个数据区的大小也会随之变化。究其规律而言,可的出如下计算公式:图像数据信息大小=(图像宽度*图像高度*记录像素的位数)/8。

通过上面的描述,我们基本上对BMP图像文件格式有一个基本的认识了,那么我们可以通过c语言的结构体的内存对齐机制来依次读取这些头文件信息,并转化成可识别的十进制信息!

首先第一步,对c语言的基本类型定义别名,方便维护。

//8bit
typedef char UINT_8;
//16bit
typedef char UINT_16[2];
//22bit
typedef char UINT_22[3];
//256bit
typedef char UINT_256[256];
//32bit
typedef int  UINT_32;
//data
typedef char* DATA;
//64 fbit
typedef double FUINT_64;
//16bit int
typedef short SUINT_16;

然后根据头信息在文件中的字节偏移地址来定义结构体:

变量名地址偏移大小作用说明
bfType0000h2Bytes
文件标识符,必须为"BM",即0x424D 才是Windows位图文件
‘BM’:Windows 3.1x, 95, NT,…  ‘BA’:OS/2 Bitmap Array  ‘CI’:OS/2 Color Icon   
‘CP’:OS/2 Color Pointer   ‘IC’:OS/2 Icon   
‘PT’:OS/2 Pointer
因为OS/2系统并没有被普及开,所以在编程时,你只需判断第一个标识“BM”就行
bfSize0002h4Bytes整个BMP文件的大小(以位B为单位)
bfReserved10006h2Bytes保留,必须设置为0
bfReserved20008h2Bytes保留,必须设置为0
bfOffBits000Ah4Bytes说明从文件头0000h开始到图像像素数据的字节偏移量(以字节Bytes为单位),以为位图的调色板长度根据位图格式不同而变化,可以用这个偏移量快速从文件中读取图像数据



变量名
地址偏移
大小
作用说明
biSize
000Eh
4Bytes
BNP信息头即BMP_INFOHEADER结构体所需要的字节数(以字节为单位)
biWidth
0012h
4Bytes
说明图像的宽度(以像素为单位)
biHeight
0016h
4Bytes
说明图像的高度(以像素为单位)。这个值还有一个用处,指明图像是正向的位图还是倒向的位图,该值是正数说明图像是倒向的即图像存储是由下到上;该值是负数说明图像是倒向的即图像存储是由上到下。大多数BMP位图是倒向的位图,所以此值是正值。
biPlanes
001Ah
2Bytes
为目标设备说明位面数,其值总设置为1
biBitCount
001Ch
2Bytes
说明一个像素点占几位(以比特位/像素位单位),其值可为1,4,8,16,24或32
biCompression
001Eh
4Bytes
说明图像数据的压缩类型,取值范围为:
0         BI_RGB 不压缩(最常用)
1         BI_RLE8 8比特游程编码(BLE),只用于8位位图
2         BI_RLE4 4比特游程编码(BLE),只用于4位位图
3         BI_BITFIELDS比特域(BLE),只用于16/32位位图
4          
biSizeImage
0022h
4Bytes
说明图像的大小,以字节为单位。当用BI_RGB格式时,总设置为0
biXPelsPerMeter
0026h
4Bytes
说明水平分辨率,用像素/米表示,有符号整数
biYPelsPerMeter
002Ah
4Bytes
说明垂直分辨率,用像素/米表示,有符号整数
biClrUsed002Eh4Bytes说明位图实际使用的调色板索引数,0:使用所有的调色板索引
biClrImportant0032h4Bytes说明对图像显示有重要影响的颜色索引的数目,如果是0,表示都重要。

注意这里一定要使用#pragma pack(1)告诉编译器结构体按1字节对齐(详细:详解C语言内存对齐)否则在读入文件流数据时会出现数据混淆的原因
//结构体
//图像结构体,防止结构体对齐否则读取文件流时出错,所以用pragma命令强制对齐
#pragma pack(1)  
typedef struct image_struct{
	UINT_16   image_pil;                //文件标识符  
	UINT_32   image_Size;               //文件大小  
	UINT_16   image_Reserved1;          //无需过问  
	UINT_16   image_Reserved2;          //无需过问  
	UINT_32   image_Offbits;            //头文件到图像数据偏移量  
	UINT_32   image_Stsize;             //结构体所需大小  
	UINT_32   image_Width;              //图像宽度  
	UINT_32   image_Height;             //图像高度  
	UINT_16   image_Planes;             //目标设备位面数  
	SUINT_16  image_Bitcount;           //像素点占用多少bit位  
	UINT_32   image_Compression;        //图像压缩类型  
	UINT_32   image_Sizeimage;          //图像的大小  
	UINT_32   image_Xpelspermeter;      //水平分辨率  
	UINT_32   image_Ypelspermeter;      //垂直分辨率  
	UINT_32   image_ClrUsed;            //调色板索引数  
	UINT_32   image_Clrlmportant;       //图像显示重要颜色索引数目  
	DATA      image_Data;               //图像数据 
	UINT_32   image_Data_Size;			//图像数据大小
}image; 
#pragma pack()  
下面开始写我们的第一个函数:image_load,加载图像文件
注意如果不使用c语言的内存对齐方式读取数据的话需要考虑大小端的问题,我们直接使用结构体来读取这样就不用考虑大小端的问题了,因为内存中的存储大小端与文件中是对应的!我们只需要直接读取到内存当中就行了!
//函数
//加载图像 
int image_load(struct image_struct** im, char *path){
	FILE *image_path_fp;
	image_path_fp = fopen(path, "rb");
	if (image_path_fp == NULL){
		return -1;
	}
	//取文件大小
	fseek(image_path_fp, 0, SEEK_END); //定位到文件末 
	int nFileLen = ftell(image_path_fp); //文件长度
	fseek(image_path_fp, 0, SEEK_SET);	//恢复到文件头,防止从文件尾读取数据
	//读取头信息
	if (fread((*im), (sizeof(struct image_struct) - ((sizeof(DATA/*image_Data*/)+(sizeof(UINT_32)/*image_Data_Size*/)))/*暂不读取数据,无法从头文件中获取数据偏移量,防止数据混乱*/), 1, image_path_fp) == 0){
		return -2;
	}
	//给data变量分配内存
	(*im)->image_Data = (DATA)malloc(nFileLen-(*im)->image_Offbits/*完整的数据大小*/);
	//判断是否分配成功
	if ((*im)->image_Data == NULL){	//如果没有可用堆内存则malloc返回NULL
		return -3;
	}
	//读取数据
	//读取前将文件指针挪移到文件头信息后,找到正确的数据存储区
	fseek(image_path_fp, 0, SEEK_SET);	//恢复到文件头,因为已经fread一次了,所以数据文件指针发生变更
	fseek(image_path_fp, (*im)->image_Offbits, SEEK_CUR);	//忽略头数据
	if (fread((*im)->image_Data, (nFileLen - (*im)->image_Offbits/*file - off = 实际大小*/), 1, image_path_fp) == 0){
		return -4;
	}
	//保存文件大小,方便读写操作
	(*im)->image_Data_Size = (nFileLen - (*im)->image_Offbits/*file - off = 实际大小*/);
	//文件指针释放,防止占用文件内核的临界资源
	fclose(image_path_fp);
	image_path_fp == NULL;
	return 0;
}
图像加载函数写完了,我们可能在使用结构体时会定义指针,所以为了方便我们在写一个用于分配内存的函数
//给图像数据分配内存
int image_malloc(struct image_struct** im){
	*im = (struct image_struct*)malloc(sizeof(struct image_struct));
	if (*im == NULL){
		return -1;
	}
	return 0;
}
还需要一个图像保存函数:
//保存图像数据到文件
int image_save_file(struct image_struct** im, char *path){
	FILE* file_fp = fopen(path, "wb+");	//以二进制可读写方式打开
	if (file_fp == NULL){	//判断文件指针是否为空
		return -1;
	}
	//写入头信息
	fwrite((*im), (*im)->image_Offbits/*直接写入头文件到数据的偏移量大小即可*/, 1, file_fp);
	//写入文件数据
	fwrite((*im)->image_Data, (*im)->image_Data_Size, 1, file_fp);
	return 0;

}
基本函数编写完成了,那么来做一个测试吧:
int main(){
	image *imga;
	image_malloc(&imga);
	image_load(&imga, "test.bmp");
	printf("图像宽度:%d\n", imga->image_Width); 
	printf("图像高度:%d\n", imga->image_Height);
	printf("图像文件占用字节:%d\n", imga->image_Size);
	printf("图像每个像素占用bit位:%d\n", imga->image_Bitcount);
	getchar();
}
完整代码:
/*Robust图像处理库
*版本:v1.0
*作者:周志豪
*4.17 19:09
*/
#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
//类型定义
//8bit  
typedef char UINT_8;
//16bit  
typedef char UINT_16[2];
//22bit  
typedef char UINT_22[3];
//256bit  
typedef char UINT_256[256];
//32bit  
typedef int  UINT_32;
//data  
typedef char* DATA;
//64 fbit  
typedef double FUINT_64;
//16bit int  
typedef short SUINT_16;
//结构体
//图像结构体,防止结构体对齐否则读取文件流时出错,所以用pragma命令强制对齐
#pragma pack(1)  
typedef struct image_struct{
	UINT_16   image_pil;                //文件标识符  
	UINT_32   image_Size;               //文件大小  
	UINT_16   image_Reserved1;          //无需过问  
	UINT_16   image_Reserved2;          //无需过问  
	UINT_32   image_Offbits;            //头文件到图像数据偏移量  
	UINT_32   image_Stsize;             //结构体所需大小  
	UINT_32   image_Width;              //图像宽度  
	UINT_32   image_Height;             //图像高度  
	UINT_16   image_Planes;             //目标设备位面数  
	SUINT_16  image_Bitcount;           //像素点占用多少bit位  
	UINT_32   image_Compression;        //图像压缩类型  
	UINT_32   image_Sizeimage;          //图像的大小  
	UINT_32   image_Xpelspermeter;      //水平分辨率  
	UINT_32   image_Ypelspermeter;      //垂直分辨率  
	UINT_32   image_ClrUsed;            //调色板索引数  
	UINT_32   image_Clrlmportant;       //图像显示重要颜色索引数目  
	DATA      image_Data;               //图像数据 
	UINT_32   image_Data_Size;			//图像数据大小
}image; 
#pragma pack()  
//函数
//加载图像 
int image_load(struct image_struct** im, char *path){
	FILE *image_path_fp;
	image_path_fp = fopen(path, "rb");
	if (image_path_fp == NULL){
		return -1;
	}
	//取文件大小
	fseek(image_path_fp, 0, SEEK_END); //定位到文件末 
	int nFileLen = ftell(image_path_fp); //文件长度
	fseek(image_path_fp, 0, SEEK_SET);	//恢复到文件头,防止从文件尾读取数据
	//读取头信息
	if (fread((*im), (sizeof(struct image_struct) - ((sizeof(DATA/*image_Data*/)+(sizeof(UINT_32)/*image_Data_Size*/)))/*暂不读取数据,无法从头文件中获取数据偏移量,防止数据混乱*/), 1, image_path_fp) == 0){
		return -2;
	}
	//给data变量分配内存
	(*im)->image_Data = (DATA)malloc(nFileLen-(*im)->image_Offbits/*完整的数据大小*/);
	//判断是否分配成功
	if ((*im)->image_Data == NULL){	//如果没有可用堆内存则malloc返回NULL
		return -3;
	}
	//读取数据
	//读取前将文件指针挪移到文件头信息后,找到正确的数据存储区
	fseek(image_path_fp, 0, SEEK_SET);	//恢复到文件头,因为已经fread一次了,所以数据文件指针发生变更
	fseek(image_path_fp, (*im)->image_Offbits, SEEK_CUR);	//忽略头数据
	if (fread((*im)->image_Data, (nFileLen - (*im)->image_Offbits/*file - off = 实际大小*/), 1, image_path_fp) == 0){
		return -4;
	}
	//保存文件大小,方便读写操作
	(*im)->image_Data_Size = (nFileLen - (*im)->image_Offbits/*file - off = 实际大小*/);
	//文件指针释放,防止占用文件内核的临界资源
	fclose(image_path_fp);
	image_path_fp == NULL;
	return 0;
}
//给图像数据分配内存
int image_malloc(struct image_struct** im){
	*im = (struct image_struct*)malloc(sizeof(struct image_struct));
	if (*im == NULL){
		return -1;
	}
	return 0;
}
//将图像转换成反向图_该方法只能用于真彩图
int image_reverse_rgb(struct image_struct** im){
	if ((*im) == NULL){	//判断传递进来的图像指针是否为空
		return -1;
	}
	//转换成反向图很简单只需要将每个图像里的像素点转换成负的就可以了,注意在一个24位的图像文件中一个字节对应一个颜色值三个字节则为一个完整的像素点,所以我们一个一个像素点的转换就可以了
	//算法公式为:S=-R-G-B
	for (int i = 0; i < (*im)->image_Data_Size; ++i){
			if ((*im)->image_Data[i] == (int)0){	//如果等于0则不处理
				continue;	//开始下一次循环
			}//i*(*im)->image_Width + j
			(*im)->image_Data[i] = -(*im)->image_Data[i];	//调用宏函数转换
	}
	return 0;
}
//保存图像数据到文件
int image_save_file(struct image_struct** im, char *path){
	FILE* file_fp = fopen(path, "wb+");	//以二进制可读写方式打开
	if (file_fp == NULL){	//判断文件指针是否为空
		return -1;
	}
	//写入头信息
	fwrite((*im), (*im)->image_Offbits/*直接写入头文件到数据的偏移量大小即可*/, 1, file_fp);
	//写入文件数据
	fwrite((*im)->image_Data, (*im)->image_Data_Size, 1, file_fp);
	return 0;

}
int main(){
	image *imga;
	image_malloc(&imga);
	image_load(&imga, "test.bmp");
	printf("图像宽度:%d\n", imga->image_Width); 
	printf("图像高度:%d\n", imga->image_Height);
	printf("图像文件占用字节:%d\n", imga->image_Size);
	printf("图像每个像素占用bit位:%d\n", imga->image_Bitcount);
	getchar();
}

运行结果:

本篇先让大家对BMP格式有一个基本的认知,和读取图像头信息中较为重要的信息
没有更多推荐了,返回首页