看到一个老外写的图像处理文章,感觉不错,翻译过来供大家参考.

时间:2021-11-29 13:02:53

(翻译了个大概,略过了一些无关紧要的句子,原文)

 

使用API调用是一种比使用VB内置图像函数更快速的方法例如,使用GetPixelSetPixel要比VBPSetPoint3倍左右但是如果使用直接内存访问(DMA)将得到更高的效率.

那么,DirectX怎么样当然DirectX是相当快的,但它的速度来自于显卡,如果你不幸地没有那么一块好显卡,或者你只是想处理简单的图像,(比如画点和线),那么DMA已经够快的了,并且能把你从麻烦的DirectX版本中解放出来.

基本思想就是直接访问图像组成你可能会想到使用GetDibitsSetDibits去费力地把图像从位图提取到数组,再把数组塞进图像而实际上,你可以将一个数组直接指向位图的内存.

要实现这样的数组当然需要用到一些API,见下:

 

使用VarPtr函数可以得到一个变量的内存地址,在此,我也引用了一个可以指向数组的函数VarPtrArray. 

使用CopyMemory则可以将数据从一块内存复制到另一块内存.

使用GetObj则可以获得一个对象的内存,在例子中我们用它来得到StdPicture对象的信息.因此,我们需要定义一个位图结构.

最后我们定义了一个安全数组结构,我们用它来替换实际工作的数组.

我们先定义StdPicture对象,并且假设它已经加载了一个图像再定义一个动态数组而不初始化我们使用API来将这个数组"分配"到图像的内存,这样,我们在数组上的任何改动就能显示在图像上了代码:

看看发生了什么首先我们用GetObj来获取了位图的信息,然后使用这个信息来构造了SafeArray2d结构,特别注意这句:

.pvdata = bmp.bmbits

它将位图位图所在的内存指向了结构.

简单把不尽然,这里有些需要注意的地方:

1:图像对象必须预先载入一个图片才能建立一个位图结构,否则它是没有意义的.

2:安全数组对象必须和数组的生存周期一致,如果你在数组被回收之前就释放了安全数组对象,那么数组将无处可指(导致VB崩溃)

3:而在释放数组之前,又必须将数组还原,否则程序会因为内存泄漏而崩溃.

4:一个256色的位图中,每个像素占用1个字节,但是这个字节只是对应了一个调色板索引而并非一个实际的颜色值所以你必须在建立数组之前先把索引转换成时机颜色.(这里不讨论16位色) 幸运的是24位色图像中存放的是真正的颜色值,但你依然需要颜色对应到RGB字节中

5:通常来说,位图对应的数组是从左下角开始的,因此数组(0,0)对应图像的最左下角的点

在你弄完之后,你必须复位数组,见下:

那么现在这个数组是什么呢?它变成了一个2维数组(X,Y),X代表横坐标,Y代表纵坐标,每一个数组元素是一个字节对于256色位图来说,这个字节是一个颜色索引,但对于24位色图像来说,它是一个颜色值每个字节对应了颜色值中的RGB中的一个,所以每个像素是有3个个数组元素组成的.例如:一个100X100的图像对应一个300X100大小的数组.

数组的大小相对于像素是不同的,因此你当你读写某个像素的时候必须自己计算:

这里给出一个速度对比:

加载一个100X10024位图像我把每个像素都设置为红色,使用DMA,SetPixelPSet时间分别为:5ms,60ms,550ms. 编译之后,分别为:4ms,50ms,70ms. DMASetPixel12

附上封装好的模块只要把它编译为ActiveX DLL然后就可以在你自己的工程中引用它.

下面是我的测试工程,演示了使用方法: