边缘检测的方法有主要有两种:
一种是基于模板匹配的,简单来说即用多个方向的检测模板与图像进行卷积,然后取邻域像素点的最大值。这种方法简单方便,容易理解,容易得到平滑的边缘,但是由于采用非常有限方向的模板(一般是8个方向,但是由于对称性可以减少为4个),因此不能检测出所有的边缘方向。
一种是基于求图像梯度的方法,一阶二阶的梯度算子,如sobel、prewitt、Robert等一阶算子和拉普拉斯算子。检测的灵敏度高,精度定位准确,但同时容易受到噪声点的影响。
Kirsch算子属于模板匹配算子,采用八个模板来处理图像的检测图像的边缘,运算量比较大。
8个3x3模板如下:



通过矩阵变换发现经过kirsch算子得到的像素值直接的关系,事实上需要直接由邻域像素点计算得到的只有p0,,因此可以大大减少计算量。



void MainWindow::on_krisch_edge_clicked()
{
Mat gradimg,gray2Img,f_1,f_2,f_3,f_4,f_5,f_6,f_7,f_8;
QImage Qtemp,Qtemp2;
gray2Img.create(grayImg.rows, grayImg.cols, CV_8UC1);
gradimg.create(grayImg.rows, grayImg.cols, CV_8UC1);
f_1.create(grayImg.rows, grayImg.cols, CV_8UC1);
f_2.create(grayImg.rows, grayImg.cols, CV_8UC1);
f_3.create(grayImg.rows, grayImg.cols, CV_8UC1);
f_4.create(grayImg.rows, grayImg.cols, CV_8UC1);
f_5.create(grayImg.rows, grayImg.cols, CV_8UC1);
f_6.create(grayImg.rows, grayImg.cols, CV_8UC1);
f_7.create(grayImg.rows, grayImg.cols, CV_8UC1);
f_8.create(grayImg.rows, grayImg.cols, CV_8UC1);
for (int i = 1; i < srcImg.rows - 1; i++)
{
for (int j = 1; j < srcImg.cols - 1; j++)
{
f_1.at<uchar>(i, j) = saturate_cast<uchar>(fabs(-5*grayImg.at<uchar>(i - 1, j - 1) -5* grayImg.at<uchar>(i - 1, j) -5* grayImg.at<uchar>(i - 1, j + 1)
+3*grayImg.at<uchar>(i, j - 1) +3*grayImg.at<uchar>(i, j + 1)
+ 3*grayImg.at<uchar>(i + 1, j - 1) + 3*grayImg.at<uchar>(i + 1, j) + 3*grayImg.at<uchar>(i + 1, j + 1)));
f_2.at<uchar>(i, j) = saturate_cast<uchar>(fabs(3*grayImg.at<uchar>(i - 1, j - 1) -5* grayImg.at<uchar>(i - 1, j) -5* grayImg.at<uchar>(i - 1, j + 1)
+3*grayImg.at<uchar>(i, j - 1) -5*grayImg.at<uchar>(i, j + 1)
+ 3*grayImg.at<uchar>(i + 1, j - 1) + 3*grayImg.at<uchar>(i + 1, j) + 3*grayImg.at<uchar>(i + 1, j + 1)));
f_3.at<uchar>(i, j) = saturate_cast<uchar>(fabs(3*grayImg.at<uchar>(i - 1, j - 1) +3* grayImg.at<uchar>(i - 1, j) -5* grayImg.at<uchar>(i - 1, j + 1)
+3*grayImg.at<uchar>(i, j - 1) -5*grayImg.at<uchar>(i, j + 1)
+ 3*grayImg.at<uchar>(i + 1, j - 1) + 3*grayImg.at<uchar>(i + 1, j) -5*grayImg.at<uchar>(i + 1, j + 1)));
f_4.at<uchar>(i, j) = saturate_cast<uchar>(fabs(3*grayImg.at<uchar>(i - 1, j - 1) +3* grayImg.at<uchar>(i - 1, j) +3* grayImg.at<uchar>(i - 1, j + 1)
+3*grayImg.at<uchar>(i, j - 1) -5*grayImg.at<uchar>(i, j + 1)
+ 3*grayImg.at<uchar>(i + 1, j - 1) -5*grayImg.at<uchar>(i + 1, j) -5*grayImg.at<uchar>(i + 1, j + 1)));
f_5.at<uchar>(i, j) = saturate_cast<uchar>(fabs(3*grayImg.at<uchar>(i - 1, j - 1) +3* grayImg.at<uchar>(i - 1, j) +3* grayImg.at<uchar>(i - 1, j + 1)
+3*grayImg.at<uchar>(i, j - 1) +3*grayImg.at<uchar>(i, j + 1)
-5*grayImg.at<uchar>(i + 1, j - 1) -5*grayImg.at<uchar>(i + 1, j) -5*grayImg.at<uchar>(i + 1, j + 1)));
f_6.at<uchar>(i, j) = saturate_cast<uchar>(fabs(3*grayImg.at<uchar>(i - 1, j - 1) +3* grayImg.at<uchar>(i - 1, j) +3* grayImg.at<uchar>(i - 1, j + 1)
-5*grayImg.at<uchar>(i, j - 1) +3*grayImg.at<uchar>(i, j + 1)
-5*grayImg.at<uchar>(i + 1, j - 1) -5*grayImg.at<uchar>(i + 1, j) +3*grayImg.at<uchar>(i + 1, j + 1)));
f_7.at<uchar>(i, j) = saturate_cast<uchar>(fabs(-5*grayImg.at<uchar>(i - 1, j - 1) +3* grayImg.at<uchar>(i - 1, j) +3* grayImg.at<uchar>(i - 1, j + 1)
-5*grayImg.at<uchar>(i, j - 1) +3*grayImg.at<uchar>(i, j + 1)
-5*grayImg.at<uchar>(i + 1, j - 1) +3*grayImg.at<uchar>(i + 1, j) +3*grayImg.at<uchar>(i + 1, j + 1)));
f_8.at<uchar>(i, j) = saturate_cast<uchar>(fabs(-5*grayImg.at<uchar>(i - 1, j - 1) -5* grayImg.at<uchar>(i - 1, j) +3* grayImg.at<uchar>(i - 1, j + 1)
-5*grayImg.at<uchar>(i, j - 1) +3*grayImg.at<uchar>(i, j + 1)
+3*grayImg.at<uchar>(i + 1, j - 1) +3*grayImg.at<uchar>(i + 1, j) +3*grayImg.at<uchar>(i + 1, j + 1)));
QVector<int> goal = {f_1.at<uchar>(i, j),f_2.at<uchar>(i, j),f_3.at<uchar>(i, j),f_4.at<uchar>(i, j),f_5.at<uchar>(i, j),f_6.at<uchar>(i, j),f_7.at<uchar>(i, j),f_8.at<uchar>(i, j)};
int max_8 = 0;
for(int i = 0 ; i<8;i++){
if(goal[i] > max_8){
max_8 = goal[i];
}
}
gradimg.at<uchar>(i, j) = max_8;
gray2Img.at<uchar>(i, j) = saturate_cast<uchar>(grayImg.at<uchar>(i, j) - gradimg.at<uchar>(i, j));
}
}
Qtemp = QImage((const uchar*)(gray2Img.data), gray2Img.cols, gray2Img.rows, gray2Img.cols*gray2Img.channels(), QImage::Format_Indexed8);
ui->label_3->setPixmap(QPixmap::fromImage(Qtemp));
Qtemp = Qtemp.scaled(250, 250, Qt::KeepAspectRatio, Qt::SmoothTransformation);
ui->label_3->setScaledContents(true);
ui->label_3->resize(Qtemp.size());
ui->label_3->show();
Qtemp2 = QImage((const uchar*)(gradimg.data), gradimg.cols, gradimg.rows, gradimg.cols*gradimg.channels(), QImage::Format_Indexed8);
ui->label_2->setPixmap(QPixmap::fromImage(Qtemp2));
Qtemp2 = Qtemp2.scaled(250, 250, Qt::KeepAspectRatio, Qt::SmoothTransformation);
ui->label_2->setScaledContents(true);
ui->label_2->resize(Qtemp2.size());
ui->label_2->show();
}