矩陣的掩碼操作很簡單眶痰。其思想是:根據(jù)掩碼矩陣(也稱作核)重新計算圖像中每個像素的值。掩碼矩陣中的值表示近鄰像素值(包括該像素自身的值)對新像素值有多大影響梯啤。從數(shù)學觀點看竖伯,我們用自己設置的權值,對像素鄰域內(nèi)的值做了個加權平均因宇。
基本方法:創(chuàng)建工具類
#import<Foundation/Foundation.h>
#import<opencv2/opencv.hpp>
#import<opencv2/imgcodecs/ios.h>
using namespace cv;
@interface OpenCVTool : NSObject
void Sharpen(const Mat& myImage,Mat& Result,int n);// 對圖片操作的方法
@end
#import "OpenCVTool.h"
@implementation OpenCVTool
void Sharpen(const Mat& myImage,Mat& Result ,int n){ ? ?
??CV_Assert(myImage.depth() == CV_8U);? ??
Result.create(myImage.size(), myImage.type());? ??
const int nChannels = myImage.channels();? ? ? ??
for (int j = 1; j < myImage.rows; ++j) {? ? ? ??
const uchar *previous = myImage.ptr(j - 1);? ? ? ??
const uchar *current = myImage.ptr(j);? ? ? ??
const uchar *next = myImage.ptr(j+1);? ? ? ? ? ? ? ??
uchar *output = Result.ptr(j);? ? ? ?
?for (int i = nChannels; i < nChannels*(myImage.cols - 1); ++i) {? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
*output++ = saturate_cast(n * current[i]- current[i - nChannels] - current[i+nChannels] - previous[i] -? ? next[i]);
//? ? ? ? ? ? *output++ = n * current[i]- current[i - nChannels] - current[i+nChannels] - previous[i] -? ? next[i];
}
}
// 邊界處理
Result.row(0).setTo(Scalar(0));
Result.row(Result.rows - 1).setTo(Scalar(0));
Result.col(0).setTo(Scalar(0));
Result.col(Result.cols - 1).setTo(Scalar(0));
}
@end
剛進入函數(shù)的時候七婴,我們需要確保輸入圖像是無符號字符類型的,為了確保這一點我們使用了CV_Assert函數(shù)察滑,若是這個函數(shù)括號內(nèi)的值為FALSE打厘。則會拋出一個錯誤。
CV_Assert(myImage.depth() == CV_8U);// 僅接受uchar的圖片
然后我們創(chuàng)建了一個與輸入有著相同大小和類型的輸出對象贺辰,我們用指針在每一個通道上迭代户盯,因此通道數(shù)就決定了需計算的元素總數(shù)。
Result.create(myImage.size(), myImage.type());
const int nChannels = myImage.channels();
利用C語言的[]操作符饲化,我們能簡單明了地訪問像素先舷。因為要同時訪問多行像素,所以我們獲取了其中每一行像素的指針(分別是前一行滓侍、當前行和下一行)。此外牲芋,我們還需要一個指向計算結果存儲位置的指針撩笆。有了這些指針后,我們使用[]操作符缸浦,就能輕松訪問到目標元素夕冲。為了讓輸出指針向前移動,我們在每一次操作之后對輸出指針進行了遞增(移動一個字節(jié)):
for (int j = 1; j < myImage.rows; ++j) {
const uchar *previous = myImage.ptr(j - 1);
const uchar *current = myImage.ptr(j);
const uchar *next = myImage.ptr(j+1);
uchar *output = Result.ptr(j);
for (int i = nChannels; i < nChannels*(myImage.cols - 1); ++i) {
*output++ = saturate_cast(n * current[i]- current[i - nChannels] - current[i+nChannels] - previous[i] -? ? next[i]);
//? ? ? ? ? ? *output++ = n * current[i]- current[i - nChannels] - current[i+nChannels] - previous[i] -? ? next[i];
}
}
在圖像的邊界上裂逐,上面給出的公式會訪問不存在的像素位置(比如(0,-1))歹鱼。因此我們的公式對邊界點來說是未定義的。一種簡單的解決方法卜高,是不對這些邊界點使用掩碼弥姻,而直接把它們設為0:
Result.row(0).setTo(Scalar(0));
Result.row(Result.rows - 1).setTo(Scalar(0));
Result.col(0).setTo(Scalar(0));
Result.col(Result.cols - 1).setTo(Scalar(0));
調(diào)用
UIImageView *imagView1 = [[UIImageView alloc] initWithFrame:CGRectMake(0, 100, self.view.bounds.size.width, 200)];
[self.view addSubview:imagView1];
UIImageView *imagView2 = [[UIImageView alloc] initWithFrame:CGRectMake(0, 350, self.view.bounds.size.width, 200)];
[self.view addSubview:imagView2];
Mat myImage,result;
UIImage *image = [UIImage imageNamed:@"try.png"];
imagView1.image = image;
UIImageToMat(image, myImage);
Sharpen(myImage, result,5);
UIImage *image2 = MatToUIImage(result);
imagView2.image = image2;
實現(xiàn)的結果
: