首先讲一下我对边缘检测原理的理解。一共分4步进行理解
- 图像数据
- 检测数据
- 形成数据
- 展示数据
图像数据
想要处理图像,首先要了解图像在内存中是如何存储的。图像是以矩阵的形式进行存储,类似一个表格,图像大小代表了表格的几行几列,每一个格子为一个像素点,像素点代表了这一个点的颜色。像素点有多种类型,单通道(灰色),3通道(RGB)等,不同的类型所占据的字节数也可能是不一致的。
检测数据
此文的所讲的算法的核心就是检测数据,检测数据有很多种方式,Sobel算子采用3*3求导的方式进行检测。下面出自网络:
http://wiki.opencv.org.cn/index.php/%E9%A6%96%E9%A1%B5
首先,我们来开一下计算机是如何检测边缘的。以灰度图像为例,它的理论基础是这样的,如果出现一个边缘,那么图像的灰度就会有一定的变化,为了方便假设由黑渐变为白代表一个边界,那么对其灰度分析,在边缘的灰度函数就是一个一次函数y=kx,对其求一阶导数就是其斜率k,就是说边缘的一阶导数是一个常数,而由于非边缘的一阶导数为零,这样通过求一阶导数就能初步判断图像的边缘了。通常是X方向和Y方向的导数,也就是梯度。理论上计算机就是通过这种方式来获得图像的边缘。
形成数据
在第二点中数据处理结果会形成新的像素点,形成新的图像,也就是我们想要得到的图像,重点提一下,像素点类型一般来说是8位无符号数IPL_DEPTH_8U,但是这里的求导结果会有负值,导致类型不满足条件会报错,这时接收图像是类型应该相应调整IPL_DEPTH_16S,或者其他满足条件的类型。
展示数据(形成图像)
就是图像转数据,数据转图像,详情看代码,重点说明要注意,像素点类型不一致会导致运行报错,在显示前要进行数据类型转换。
效果图
运行代码
xx.h
#pragma once
#include "cv.h"
#include <opencv2/highgui/highgui.hpp>
#include "main.h"
void mainCv();
xx.cpp
#include "opencvCv.h"
using namespace cv;
void jSobel() {
IplImage *frame, *gray, *sobel;
frame = cvLoadImage("wood.jpg");//加载图像
gray = cvCreateImage(cvGetSize(frame), frame->depth, 1);
sobel = cvCreateImage(cvGetSize(frame), IPL_DEPTH_16S, 1);
cvNamedWindow("frame");
cvNamedWindow("gray");
cvNamedWindow("sobel");
cvCvtColor(frame, gray, CV_BGR2GRAY);//转为灰度
cvSobel(gray, sobel, 1, 0, 3);
IplImage *sobel8u = cvCreateImage(cvGetSize(sobel), IPL_DEPTH_8U, 1);
cvConvertScaleAbs(sobel, sobel8u, 1, 0);
cvShowImage("frame", frame);//显示图像
cvShowImage("gray", gray);
cvShowImage("sobel", sobel8u);
cvWaitKey(0);//等待
cvReleaseImage(&frame);
cvReleaseImage(&gray);
cvReleaseImage(&sobel);
cvDestroyWindow("frame");
cvDestroyWindow("gray");
cvDestroyWindow("sobel");
}