OpenCV 学习(像素操作 2)
2015-10-05 16:57
615 查看
在上一个学习笔记中,简单介绍了访问图像像素的几种方法,并对这几种方法的效率进行了些简单的比较。但是更多的情况是我们要同时访问多个像素,经过较为复杂的运算才能得到我们希望的结果。今天就来讲讲这种情况如何处理。
⎛⎝⎜0−10−15−10−10⎞⎠⎟
可以看到,计算当前点的输出时需要上下左右 4 邻近点的值。这时最简单的想法就是同时用三个指针,分别指向当前行、上一行和下一行。下面是个例子代码:
有几点需要说明:
这个函数只对灰度图像有效。
应为对原始图像我们只是读取而不改变其值,所以用的是 const uchar* 型的指针。
运算结果有可能会超出 uchar 型能够表示的范围,所以程序中用了 cv::saturate_cast () 将超出的部分截断。
图像的四条边框没有计算,而是直接填充了 0 值。
原始图像和处理后的图像对比如下:
如果要处理彩色图像,可以这样写:
或者还是用 uchar 型来处理:
实际上,上面的操作还可以使用 cv::filter2D 函数来做。代码会非常简洁,而且计算速度也是最快的。
处理前后的图像对比如下:
同时访问多行像素数据
下面我们以laplace 锐化为例,Laplacian 算子写为矩阵形式如下:⎛⎝⎜0−10−15−10−10⎞⎠⎟
可以看到,计算当前点的输出时需要上下左右 4 邻近点的值。这时最简单的想法就是同时用三个指针,分别指向当前行、上一行和下一行。下面是个例子代码:
void sharpen(const cv::Mat &image, cv::Mat &result) { // allocate if necessary result.create(image.size(), image.type()); for (int j = 1; j < image.rows - 1; j++) { // for all rows // (except first and last) const uchar* previous = image.ptr<const uchar>(j-1); // previous row const uchar* current = image.ptr<const uchar>(j); // current row const uchar* next = image.ptr<const uchar>(j+1); // next row uchar* output= result.ptr<uchar>(j); // output row for (int i=1; i<image.cols-1; i++) { *output++= cv::saturate_cast<uchar>( 5 *current[i] - current[i-1] - current[i+1] - previous[i] - next[i]); } } // Set the unprocess pixels to 0 result.row(0).setTo(cv::Scalar(0)); result.row(result.rows-1).setTo(cv::Scalar(0)); result.col(0).setTo(cv::Scalar(0)); result.col(result.cols-1).setTo(cv::Scalar(0)); }
有几点需要说明:
这个函数只对灰度图像有效。
应为对原始图像我们只是读取而不改变其值,所以用的是 const uchar* 型的指针。
运算结果有可能会超出 uchar 型能够表示的范围,所以程序中用了 cv::saturate_cast () 将超出的部分截断。
图像的四条边框没有计算,而是直接填充了 0 值。
原始图像和处理后的图像对比如下:
如果要处理彩色图像,可以这样写:
void sharpen1(const cv::Mat &image, cv::Mat &result) { // allocate if necessary result.create(image.size(), image.type()); int nr = image.rows; int nl = image.cols; for (int j = 1; j < nr - 1; j++) { // for all rows // (except first and last) const cv::Vec3b* previous = image.ptr<const cv::Vec3b>(j-1); // previous row const cv::Vec3b* current = image.ptr<const cv::Vec3b>(j); // current row const cv::Vec3b* next = image.ptr<const cv::Vec3b>(j+1); // next row cv::Vec3b* output= result.ptr<cv::Vec3b>(j); // output row for (int i = 1; i<nl - 1; i++) { output[i][0] = cv::saturate_cast<uchar>( 5 *current[i][0] - current[i - 1][0] - current[i + 1][0] - previous[i][0] - next[i][0]); output[i][1] = cv::saturate_cast<uchar>( 5 *current[i][1] - current[i - 1][1] - current[i + 1][1] - previous[i][1] - next[i][1]); output[i][2] = cv::saturate_cast<uchar>( 5 *current[i][2] - current[i - 1][2] - current[i + 1][2] - previous[i][2] - next[i][2]); } } // Set the unprocess pixels to 0 result.row(0).setTo(cv::Vec3b(0, 0, 0)); result.row(result.rows-1).setTo(cv::Vec3b(0, 0, 0)); result.col(0).setTo(cv::Vec3b(0, 0, 0)); result.col(result.cols-1).setTo(cv::Vec3b(0, 0, 0)); }
或者还是用 uchar 型来处理:
void sharpen2(const cv::Mat &image, cv::Mat &result) { // allocate if necessary result.create(image.size(), image.type()); int nr = image.rows; int nl = image.cols * image.elemSize(); int stride = image.elemSize(); for (int j = 1; j < nr - 1; j++) { // for all rows // (except first and last) const uchar* previous = image.ptr<const uchar>(j-1); // previous row const uchar* current = image.ptr<const uchar>(j); // current row const uchar* next = image.ptr<const uchar>(j+1); // next row uchar* output= result.ptr<uchar>(j); // output row for (int i = stride; i < nl - stride; i++) { *output++= cv::saturate_cast<uchar>( 5 *current[i] - current[i - stride] - current[i + stride] - previous[i] - next[i]); } } // Set the unprocess pixels to 0 result.row(0).setTo(cv::Vec3b(0, 0, 0)); result.row(result.rows-1).setTo(cv::Vec3b(0, 0, 0)); result.col(0).setTo(cv::Vec3b(0, 0, 0)); result.col(result.cols-1).setTo(cv::Vec3b(0, 0, 0)); }
实际上,上面的操作还可以使用 cv::filter2D 函数来做。代码会非常简洁,而且计算速度也是最快的。
void sharpen2D(const cv::Mat &image, cv::Mat &result) { // Construct kernel (all entries initialized to 0) cv::Mat kernel(3, 3, CV_32F, cv::Scalar(0)); // assigns kernel values kernel.at<float>(1,1) = 5.0; kernel.at<float>(0,1) = -1.0; kernel.at<float>(2,1) = -1.0; kernel.at<float>(1,0) = -1.0; kernel.at<float>(1,2) = -1.0; //filter the image cv::filter2D(image, result, image.depth(), kernel); }
处理前后的图像对比如下:
相关文章推荐
- python中使用OpenCV进行人脸检测的例子
- opencv 做人脸识别 opencv 人脸匹配分析
- 使用opencv拉伸图像扩大分辨率示例
- OpenCV 2.4.3 C++ 平滑处理分析
- 利用Python和OpenCV库将URL转换为OpenCV格式的方法
- python结合opencv实现人脸检测与跟踪
- 在树莓派2或树莓派B+上安装Python和OpenCV的教程
- OpenCV配置,从来没有这么简单!
- ubuntu下opencv和qt的安装配置
- OpenCV学习笔记(二十五)——OpenCV图形界面设计Qt+VS2008
- 分享一些OpenCV实现立体视觉的经验
- 关于OpenCv图像变换与基本图形检测
- "应用程序正常初始化失败"-0xc0150002 解决办法
- OpenCV->HSV色彩空间
- opencv 内存泄露
- OpenCV函数cvFindContours
- OpenCV 2.3.1图像文件的读入和显示
- opencv2 矩阵方式 resize图像缩放代码
- OpenCV 灰度直方图
- 彩色图转为灰度图