拉普拉斯算子(Laplacian)可应用到图像边缘检测中。在OpenCV中当kernel大小为3*3时,支持两种kernel算子,分别为:

在OpenCV中默认的计算方式如下,假设有一个5*5的小图像,原始值依次为1,2,…25,如下图红色部分,首先将5*5映射到(5+3-1)*(5+3-1)大小,然后和3*3的kernel做累积和,因为计算结果有可能超出有效值[0, 255]范围,因此在最终还需要判断使其在有效范围内,即小于0为0,大于255为255:

如坐标为(0,0)的计算过程为:12 = 7*0+6*1+7*0+2*1+1*(-4)+2*1+7*0+6*1+7*0.

以下code分别采用两种方式实现,一种是从OpenCV中提取的code(Laplacian_函数),一种是按照上面说明的方式实现的(Laplacian函数),两种方式实现的结果完全一致,但第二种方式更容易理解:

laplacian.cpp:#include "funset.hpp"

#include

#include

#include

#include

#include

#include "common.hpp"

namespace {

typedef struct Rect {

int x, y, width, height;

} Rect;

typedef struct Size {

int width, height;

} Size;

typedef struct Point {

int x, y;

} Point;

int borderInterpolate(int p, int len)

{

if ((unsigned)p

;

} else {

if (len == 1) return 0;

int delta = 1;

do {

if (p

else p = len - 1 - (p - len) - delta;

} while ((unsigned)p >= (unsigned)len);

}

return p;

}

inline unsigned char saturate_cast(float v)

{

int iv = (int)(v + (v >= 0 ? 0.5f : -0.5f));

return (unsigned char)((unsigned)v <= UCHAR_MAX ? v : v > 0 ? UCHAR_MAX : 0);

}

void filter2D(const unsigned char** src, unsigned char* dst, int dststep, int count, int width, int ksize)

{

std::vector coords;

std::vector coeffs;

if (ksize == 1) {

coords = { { 1, 0 }, { 0, 1 }, { 1, 1 }, { 2, 1 }, { 1, 2 } }; // kernel non zero position: (x, y)

coeffs = { 1.f, 1.f, -4.f, 1.f, 1.f }; // kernel non zero value: 1, 1, -4, 1, 1

} else {

coords = { { 0, 0 }, { 2, 0 }, { 1, 1 }, { 0, 2 }, { 2, 2 } }; // kernel non zero position: (x, y)

coeffs = { 2.f, 2.f, -8.f, 2.f, 2.f }; // kernel non zero value: 2, 2, -8, 2, 2

}

std::vector ptrs(coords.size());

float _delta{ 0.f };

const Point* pt = &coords[0];

const float* kf = (const float*)&coeffs[0];

const unsigned char** kp = (const unsigned char**)&ptrs[0];

int nz = (int)coords.size();

for (; count > 0; count--, dst += dststep, src++) {

unsigned char* D = (unsigned char*)dst;

for (int k = 0; k

kp[k] = (const unsigned char*)src[pt[k].y] + pt[k].x;

for (int i = 0; i

float s0 = _delta;

for (int k = 0; k

s0 += kf[k] * kp[k][i];

D[i] = saturate_cast(s0);

}

}

}

int Laplacian_(const unsigned char* src_, unsigned char* dst_, int width_, int height_, int ksize_)

{

const unsigned char* src = src_;

unsigned char* dst = dst_;

const Size ksize{ 3, 3 };

const int maxBufRows = ksize.height + 3;

const Point anchor{ 1, 1 };

const Rect roi{ 0, 0, width_, height_ };

const int dx1{ 1 }, dx2{ 1 };

int borderLength = std::max(ksize.width - 1, 1);

std::vector borderTab(borderLength);

borderTab[0] = borderInterpolate(-dx1, width_);

borderTab[1] = borderInterpolate(width_, width_);

std::vector rows(maxBufRows);

const int* btab = &borderTab[0];

int srcstep{ width_ }, dststep{ width_ };

std::vector ringBuf((width_ + ksize.width - 1) * maxBufRows, 0);

int bufStep{ width_ + ksize.width - 1 };

int startY = std::max(roi.y - anchor.y, 0), startY0 = startY, rowCount{ 0 }, dstY{ 0 };

int endY = std::min(roi.y + roi.height + ksize.height - anchor.y - 1, height_);

int esz = 1;

unsigned char** brows = &rows[0];

int bufRows = (int)rows.size();

int kwidth = ksize.width;

int kheight = ksize.height, ay = anchor.y;

int _dx1 = dx1, _dx2 = dx2;

int width1 = roi.width + kwidth - 1;

int dy = 0, i = 0;

int count = endY - startY;

for (;; dst += dststep * i, dy += i) {

int dcount = bufRows - ay - startY - rowCount + roi.y;

dcount = dcount > 0 ? dcount : bufRows - kheight + 1;

dcount = std::min(dcount, count);

count -= dcount;

for (; dcount-- > 0; src += srcstep) {

int bi = (startY - startY0 + rowCount) % bufRows;

unsigned char* brow = &ringBuf[0] + bi*bufStep;

unsigned char* row = brow;

if (++rowCount > bufRows) {

--rowCount;

++startY;

}

memcpy(row + _dx1*esz, src, (width1 - _dx2 - _dx1)*esz);

for (i = 0; i

row[i] = src[btab[i]];

for (i = 0; i

row[i + (width1 - _dx2)*esz] = src[btab[i + _dx1*esz]];

}

int max_i = std::min(bufRows, roi.height - (dstY + dy) + (kheight - 1));

for (i = 0; i

int srcY = borderInterpolate(dstY + dy + i + roi.y - ay, height_);

if (srcY

if (srcY >= startY + rowCount) break;

int bi = (srcY - startY0) % bufRows;

brows[i] = &ringBuf[0] + bi*bufStep;

}

if (i

i -= kheight - 1;

filter2D((const unsigned char**)brows, dst, dststep, i, roi.width, ksize_);

}

dstY += dy;

if (dstY > roi.height) return -1;

return 0;

}

int Laplacian(const unsigned char* src_, unsigned char* dst_, int width_, int height_, int ksize_)

{

const int kernel_size{ 3 };

std::vector kernel;

if (ksize_ == 1) kernel = { 0.f, 1.f, 0.f, 1.f, -4.f, 1.f, 0.f, 1.f, 0.f };

else kernel = { 2.f, 0.f, 2.f, 0.f, -8.f, 0.f, 2.f, 0.f, 2.f };

int new_width = width_ + kernel_size - 1, new_height = height_ + kernel_size - 1;

std::unique_ptr data(new unsigned char[new_width * new_height]);

unsigned char* p = data.get();

for (int y = 0; y

if (y != 0 && y != new_height - 1) {

for (int x = 0; x

if (x == 0) {

p[y * new_width + x] = src_[(y - 1) * width_ + 1];

} else if (x == new_width - 1) {

p[y * new_width + x] = src_[(y - 1) * width_ + (width_ - 1 - 1)];

} else {

p[y * new_width + x] = src_[(y - 1) * width_ + (x - 1)];

}

}

}

if (y == new_height - 1) {

for (int x = 0; x

p[y * new_width + x] = p[(y - 2) * new_width + x];

}

for (int x = 0; x

p[x] = p[2 * new_width + x];

}

}

}

for (int y = 1; y

for (int x = 1; x

float value{ 0.f };

int count{ 0 };

for (int m = -1; m <= 1; ++m) {

for (int n = -1; n <= 1; ++n) {

value += p[(y + m) * new_width + (x + n)] * kernel[count++];

}

}

if (value

else if (value > 255.) dst_[(y - 1) * width_ + (x - 1)] = 255;

else dst_[(y - 1) * width_ + (x - 1)] = static_cast(value);

}

}

return 0;

}

} // namespace

int laplacian_cpu(const unsigned char* src, int width, int height, int ksize, unsigned char* dst, float* elapsed_time)

{

int ret{ -1 };

// ksize == 1: kernel={ 0, 1, 0, 1, -4, 1, 0, 1, 0 }

// ksize == 3: kernel={ 2, 0, 2, 0, -8, 0, 2, 0, 2 }

CHECK(ksize == 1 || ksize == 3);

//TIME_START_CPU

ret = Laplacian(src, dst, width, height, ksize);

//TIME_END_CPU

return ret;

}

main.cpp:#include "funset.hpp"

#include

#include

#include

#include

#include

#include

#include "common.hpp"

int test_image_process_laplacian()

{

cv::Mat src = cv::imread("E:/GitCode/CUDA_Test/test_data/images/lena.png", 0);

if (!src.data || src.channels() != 1) {

fprintf(stderr, "read image fail\n");

return -1;

}

int width{ 400 }, height{ 400 };

cv::resize(src, src, cv::Size(width, height));

std::unique_ptr data1(new unsigned char[width * height]), data2(new unsigned char[width * height]);

float elapsed_time1{ 0.f }, elapsed_time2{ 0.f }; // milliseconds

int ksize{ 1 };

CHECK(laplacian_cpu(src.data, width, height, ksize, data1.get(), &elapsed_time1) == 0);

//CHECK(laplacian_gpu(src.data, width, height, data2.get(), &elapsed_time2) == 0);

//fprintf(stdout, "gray image edge detection: laplacian: cpu run time: %f ms, gpu run time: %f ms\n", elapsed_time1, elapsed_time2);

cv::Mat dst;

cv::Laplacian(src, dst, src.depth(), ksize);

cv::imwrite("E:/GitCode/CUDA_Test/test_data/images/laplacian.png", dst);

CHECK(compare_result(data1.get(), dst.data, width*height) == 0);

//CHECK(compare_result(data1.get(), data2.get(), width*height) == 0);

save_image(src, dst, width, height / 2, "E:/GitCode/CUDA_Test/test_data/images/laplacian_result.png");

return 0;

}

执行结果如下:

由结果可知:C++实现结果和调用OpenCV的接口结果是完全一致的。

基于c语言图像边缘检测的程序,图像边缘检测之拉普拉斯(Laplacian)C++实现相关推荐

  1. c语言逻辑运用及宏程序编写,基于C语言基础的宏程序编程

    基于C语言基础的宏程序编程 王恒厂,周燕飞,姚裕,吕常奎 (南京航空航天大学工程训练中心,江苏南京211100) 摘 要:用户宏指令编程是FANUC系统所提供的一种先进的编程方法[1],使用变量代替程 ...

  2. 基于go语言结合微信小程序开发的微商城系统

    最近我录制的一门<Golang微信小程序微商城系统原型>,这门免费课程特别适合在校大学生或者刚毕业的大学生,go语言初学者以及想要从事微商城开发项目入门的小伙伴们来学习.在课程当中我不仅仅 ...

  3. 图像分块matlab程序,图像分块 matlab程序

    clear,clc; [filename,filepath] = uigetfile('*.*','Select the image'); if isequal(filename,0)||isequa ...

  4. 基于c语言抓包软件程序,C或者C++写的抓包工具。

    满意答案 给你一个winpcap的示例代码,具体的可以根据自己的需求修改 #include #include #include #define LINE_LEN 16 int main(int arg ...

  5. 基于c语言的图像边缘检测,基于C语言的医学图像处理的设计

    内容介绍 原文档由会员 莎士比亚 发布 资源包括:正文DOC格式共41页 19611字 摘 要:B超图像作为医学图像的一个部分,具有医学数字图像的某些共性.B超图像处理技术作为医学数字图像处理技术的一 ...

  6. 图像haar特征提取 c语言,基于C语言的特征点提取程序 本程序是利用C语言对各种信号数据的特征点提取程序 - 下载 - 搜珍网...

    基于C语言的特征点提取程序\修改后 特征点提取程序\提取特征点\Debug\football.ilk 基于C语言的特征点提取程序\修改后 特征点提取程序\提取特征点\Debug\football.ob ...

  7. 基于c语言矩阵数组透视变换,一种图像透视变换方法与流程

    本发明属于图像处理的技术领域,尤其涉及一种图像透视变换方法. 背景技术: 透视变换是一种常见图像处理方法.透视变换常用于图象的校正,例如在移动机器人视觉导航研究中,由于摄像机与地面之间有一倾斜角,而不 ...

  8. C语言数字图像处理----3.2 图像边缘检测之Canny边缘检测算法

    本篇将介绍图像边缘检测中的Canny边缘检测,这是传统边缘检测学习中的必学内容,也是图像算法面试中的常见问题,本文将教会初学者如何在理解算法的基础之上,通过C语言来实现Canny边缘检测算法,从而做到 ...

  9. 对彩色花图像进行分类-基于R语言的Keras实现

    该案例摘自<Keras深度学习入门.实战及进阶>第四章综合案例内容. 该案例的数据来源于Kaggle上的Flower Color Images(https://www.kaggle.com ...

最新文章

  1. CTFshow 命令执行 web120
  2. 前端dashboard框架_微前端在网易七鱼的实践
  3. 小学计算机说课稿,小学信息技术说课稿《新建文件夹》
  4. string’ does not name a type 错误解析
  5. UVA-11988 悲剧文本-静态链表
  6. 简单c语言课设计题目,C语言课程设计题目
  7. 某单位会java_Java核心API -- 4(日期类)
  8. LeetCode 1609. 奇偶树(层序遍历)
  9. 数据算法之二叉树删除(BinaryTreeL Remove)的Java实现
  10. Judge whether the user is in some windows group.
  11. 数据结构【图】—023邻接表深度和广度遍历
  12. Demo之JavaEE的Web中数据分页显示
  13. RuiJie命令行划VLAN
  14. 2021考研数学二汤家凤接力题典1800【题目册】
  15. arma 预测 matlab代码,求助:ARMA模型进行预测
  16. java 网站 分类
  17. GeForce GTX 1050-2G驱动安装
  18. JS实现复制页面文字弹出消息提醒/在sweetalert(swal)弹出窗插件中加入html代码
  19. 超文本咖啡壶控制协议
  20. 如何炸掉……呃,月球?

热门文章

  1. 西游记中孙悟空的等级地位
  2. 若要运行此应用程序 您必须首先安装 .NET Framework的以下版本之一
  3. Infragistics控件使用
  4. TensorFlow入门教程(16)分离歌曲中的人声和背景音乐
  5. setlocale(LC_ALL,) 中的 LC_* 是什么意思,以及 LANGUAGE/LANG 都是些啥?
  6. Docker 镜像管理
  7. HTML5文字转语音源码,微软TTS语音源码(将文本转为语音并播放)
  8. 怎么在抖音中一键复制微信号打开微信引流
  9. 第一百篇博客,想谈谈大学的前端的学习历程和未来的计划
  10. 企业即时通讯软件有哪些功能?对企业有什么帮助?