上一章介紹的色彩空間轉換,都是使用一維陣列處理,接著因為要用到類似捲積的方式去做濾鏡,所以將一維陣列轉為二維陣列存取能增加可讀性,而在轉二維陣列之前要先實現填補功能,而在OpenCV函數為copyMakeBorder,它有很多不同的填補類型,今天我們要做的單純補上0跟捲積處理方式一樣,以下開始介紹填補。
這裡使用到Assert是方便進行Debug(單元測試也很好用),主要將自己認為絕對不可能地排除在外,若不成立則會跳出錯誤訊息,詳細使用可到assert觀看,而[1]提到加入#define NDEBUG,assert就會關閉(assert也會吃效能,發行通常會關閉)。
填補是將上下左右擴充到需要的大小,假如填補為1,如下圖,可以看到要填補的地方為紅色和藍色,而在C++能使用拷貝記憶體值的函數memcpy來去達成,輸出圖的大小則是在C#函數處理好,為了記憶體方便自己控管盡量不要在C++回傳指標。
輸出圖大小為:(輸入圖寬 + 2 * padding) * (輸入圖高 + 2 * padding)。
C++加入ImagePadding8bit函數:
標頭檔:Library.h
/*
ImagePadding8bit Parameter:
src = source of image
pur = purpose of image
width = Image's width
height = Image's height
pad = padding size
*/
void ImagePadding8bit(C_UCHAE* src, UCHAE* pur
, C_UINT32 width, C_UINT32 height
, C_INT32 pad);
加入實作檔:Library.cpp
void Library::ImagePadding8bit(C_UCHAE* src, UCHAE* pur
, C_UINT32 width, C_UINT32 height
, C_INT32 pad)
{
assert(src != nullptr && pur != nullptr);
assert(width > 0 && height > 0);
assert(pad >= 0);
C_UINT32 copySize = width * sizeof(UCHAE);
C_UINT32 purWidth = (width + 2 * pad);
C_UCHAE* srcEnd = src + width * height;
pur += (pad * purWidth) + pad;
while (src < srcEnd)
{
memcpy(pur, src, copySize);
pur += purWidth;
src += width;
}
}
C#加入mndtImagePadding8bit函數:
MNDTLibrary.cs
[DllImport(DLL_PATH)]
unsafe private static extern void mndtImagePadding8bit(IntPtr src, IntPtr pur, int width, int height, int pad);
public Bitmap ImagePadding8bit(Bitmap srcImage, int pad)
{
Bitmap purImage = new Bitmap(srcImage.Width + pad * 2, srcImage.Height + pad * 2, PixelFormat.Format8bppIndexed);
Rectangle size = new Rectangle(0, 0, srcImage.Width, srcImage.Height);
BitmapData srcData = srcImage.LockBits(size, ImageLockMode.ReadOnly, PixelFormat.Format8bppIndexed);
BitmapData purData = purImage.LockBits(size, ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed);
unsafe
{
IntPtr srcPtr = srcData.Scan0;
IntPtr purPtr = purData.Scan0;
mndtImagePadding8bit(srcPtr, purPtr, srcImage.Width, srcImage.Height, pad);
}
purImage.Palette = _colorPalette;
srcImage.UnlockBits(srcData);
purImage.UnlockBits(purData);
return purImage;
}
呼叫方式,先轉為灰階8bit。
Bitmap bitmap = _lib.Change8BitColor(_fileImage, ColerType.BGR2GRAY_8BIT);
pic_pur.Image = _lib.ImagePadding8bit(bitmap, 10);
目前只有長、寬和二維指標。
主要建立height大小指標指向每個width的第一個,解構式記得要刪除指標並指向nullptr。
新增標頭檔:Image.h
#pragma once
#ifndef IMAGE_H
#define IMAGE_H
#include "general.h"
class Image
{
public:
/*
Image Parameter:
src = source of image
width = Image width
height = Image height
type = Image type
*/
Image(UCHAE* src
, C_UINT32 width, C_UINT32 height
, C_UINT32 type);
~Image();
UINT32 Width() const;
UINT32 Height() const;
UCHAE** image;
private:
MNDT::ImageType _type;
UINT32 _width;
UINT32 _height;
};
#endif // !IMAGE_H
新增實作檔:Image.cpp
#include "Image.h"
Image::Image(UCHAE* src
, C_UINT32 width, C_UINT32 height
, C_UINT32 type)
{
_width = width;
_height = height;
_type = static_cast<MNDT::ImageType>(type);
image = new UCHAE*[height];
for (UINT32 index = 0; index < height; index++)
{
*(image + index) = (src + width * index);
}
}
Image::~Image()
{
delete[] image;
image = nullptr;
}
UINT32 Image::Width() const
{
return _width;
}
UINT32 Image::Height() const
{
return _height;
}
接著就可以開始介紹各式各樣的濾波器,後面使用濾波器的頻率會很大所以必須先知道這些方便往後處理,若有問題歡迎提問和指導。
[1]http://www.cplusplus.com/reference/cassert/assert/