Thuật giải lọc Gaussian
Ký hiệu
_srcImg
: Ảnh gốc kích thước:RI x CI
._kernel
: Kernel, mảng một chiều có số phần tửRK x CK
.sigma
: Độ lệch chuẩn của hàmgauss
.
Giải thuật
Bước 1
- Tính toán ma trận kernel của toán tử gaussian theo công thức.

- Tính chỉ số truy cập nhanh
_kernelIndex
, sử dụng trong Tích Chập. - Mỗi phần tử là một
Point
vớix
là chỉ số dòng vày
là chỉ số cột. Anchor point
có toạ độ (0, 0).
Bước 2
- Tính tổng giá trị của tất cả các phần tử trong ma trận kernel lưu vào
sumKer
. Dành cho việc chuẩn hoá giá trị của mỗi phần tử trong kernel.
sumKer := sum(_kernel); IF sumKer == 0: sumKer := 1;
- Chuẩn hoá: chia mỗi phần tử trong
_kernel
chosumKer
:
_kernel.element := _kernel.element / sumKer;
Bước 3
Thực hiện convolution _kernel
với _srcImg
cho ảnh kết quả _destImg
:
For each pixel pS in _srcImg: For each element eK in _kernel: _destImg[pS] += _kernel[eK] * _srcImg[pS - _kernelIndex[eK]]; End For End For
Hiện thực giải thuật
Trong quá trình hiện thực giải thuật, một số bước không tuân theo do quan tâm đến thời gian thực thi của chương trình. Như trong bước 2, không thực hiện chuẩn hoá kernel ngay. Mà thực hiện tích chập trước, kết quả tích chập sẽ đem chia cho sumKer
.
Tính toán ma trận kernel
/* * @Brief: function to create kernel for gaussian filter. With height, width, sigma input by users. * @Param[out]: kernel: vector with size = 0. * @Param[in]: height: Numbers of row of matrix kernel will be created. Should: Odd value. * @Param[in]: width: Numbers of column of matrix kernel will be created. Should: Odd value. * @Param[in]: sigma: Standard deviation of gaussian funct. * @Retval: None. */ void TEST::createGaussianKernel(vector<float> & kernel, int height, int width, float sigma) { float inverse_Sqrt2Pi_Sigma; float inverse_2_SigmaSquare; int indexRow, indexCol; inverse_Sqrt2Pi_Sigma = 1 / (sqrt(2 * PI) * sigma); inverse_2_SigmaSquare = 1 / (2 * sigma * sigma); for (indexRow = -height / 2; indexRow < ((height - 1) / 2) + 1; indexRow++) { for (indexCol = -width / 2; indexCol < ((width - 1) / 2) + 1; indexCol++) { kernel.push_back(inverse_Sqrt2Pi_Sigma * exp(-(indexRow * indexRow + indexCol * indexCol) * inverse_2_SigmaSquare )); } } }
Tính toán _kernelIndex và sumKer
for (int i = -(_kernelHeight / 2); i < ((_kernelHeight - 1) / 2) + 1; i++) for (int j = -(_kernelWidth / 2); j < ((_kernelWidth - 1) / 2) + 1; j++) { _kernelIndex.push_back(Point(i, j)); _sumKernel += _kernel[ii++]; } if (_sumKernel == 0) _sumKernel = 1;
Thực hiện convolution _kernel
Thực hiện convolution _kernel
với _srcImg
cho ảnh kết quả _destImg
void Convolution::doConvolution(Mat& sourceImage, Mat& destinationImage) { int numRowImg = sourceImage.rows; int numColImg = sourceImage.cols; int indexRow, indexCol, indexKernel, indexRImg, indexCImg; float g_val; destinationImage.create(Size(numColImg, numRowImg), CV_8UC1); for (indexRow = 0; indexRow < numRowImg; indexRow++) { uchar* data = destinationImage.ptr<uchar>(indexRow); for (indexCol = 0; indexCol < numColImg; indexCol++) { g_val = 0; for (indexKernel = 0; indexKernel < _kernel.size(); indexKernel++) { indexRImg = indexRow - _kernelIndex[indexKernel].x; if (indexRImg < 0 || indexRImg > numRowImg - 1) continue; indexCImg = indexCol - _kernelIndex[indexKernel].y; if (indexCImg < 0 || indexCImg > numColImg - 1) continue; g_val += _kernel[indexKernel] * sourceImage.at<uchar>(indexRImg, indexCImg); } data[indexCol] = saturate_cast<uchar> (g_val / _sumKernel); } } }
Bước tiếp theo, tạo giao diện đơn giản để chạy thuật toán này. Thực ra, nếu chỉ chạy thuật toán này thôi thì không cần tạo giao diện, chỉ cần OpenCV là đủ. Tuy nhiên, bài viết hướng dẫn tạo giao diện cho một project với nhiều tác vụ.
Tạo Project với Qt + OpenCV
Bài viết này sử dụng các phiên bản phần mềm như sau:
- Windows 10 - 64bit.
- Visual Studio 2013 community - 32bit.
- Qt 5.5.0 for Windows 32 bit.
- OpenCV 3.0.
Cài đặt và tạo project Qt
Cài đặt và cấu hình thư viện OpenCV cho project
OpenCV – Cài Đặt Và Ví Dụ Minh Họa Sử Dụng
Thiết kế giao diện

Ở cây thư mục project TEST click chọn test.ui và kéo thả như hình dưới:

Build chương trình sẽ tự động write lại các file trong Filter folder Generated Files.
Thiết kế Class

Class TEST (test.h, test.cpp):
ui
: quản lý giao diện. Hàmui.setUI
được gọi trong hàm khởi tạo củaclass TEST
._sourceImg
: lưu ảnh gốc._destImg
: lưu ảnh sau khi làm mờ.createGaussianKernel
: hàm tạo ma trận kernel với kích thước và độ lệch chuẩn do người dùng định.connectObject
: hàm thực hiện kết nối tất cả các thông quasignals
vàslots
buttonQObject
(ChooseImage
vàGaussianBlur
). Hàm được gọi trong hàm khởi tạo của lớp.- slots
openImage
: được gọi khi người dùng click chọn buttonChoose
Image
. Hàm hiển thị dialog để chọn ảnh thực hiện làm mờ. - slots
doConvo
: được gọi khi người dùng click chọn buttonGaussian Blur
. Hàm thực hiện:createGaussianKernel
→Convo.setKernel
(đối tượngConvo
thuộc lớpConvolution
) →Convo.doConvolution
→ Hiển thị kết quả.
Class Convolution
(convolution.h
, convolution.cpp
): được trình bày như trên giải thuật.
Kết quả
Kết quả thực hiện với kernel(5x5)
, sigma = 2
.
Theo thứ tự từ trái qua phải:
- Ảnh gốc.
- Ảnh thực hiện bởi thuật giải.
- Ảnh thực hiện bởi hàm GaussianBlur của thư viện OpenCV.
