opencv_cuda版本+cuda学习 (4)图像的腐蚀与膨胀

1.二值图像的腐蚀

腐蚀模板算子,中心和周围8个点,如果周围有像素点为0,则中心点为0。全255,才为255

核函数:

template<int nthreads>
__global__ void compute_kernel(int height, int width, const PtrStepb img, PtrStepb dst) {

	//	1.图像二值化
	const int ix = blockIdx.x * blockDim.x + threadIdx.x;
	const int iy = blockIdx.y * blockDim.y + threadIdx.y;
	const uchar* src_yy = (const uchar*)(img + iy * img.step);
	uchar* dst_yy = (uchar*)(dst + iy * dst.step);

	if (ix < width && iy < height) {
		if (src_yy[ix] >= 130)
			dst_yy[ix] = 255;
		else
			dst_yy[ix] = 0;
	}

	//利用二值图实现图像膨胀
	const uchar* src_y = (const uchar*)(img);
	uchar* dst_y = (uchar*)dst;

	int ix_1 = max(0, ix - 1);
	int ix1 = min(width - 1, ix + 1);
	int iy_1 = max(0,iy - 1);
	int iy1 = min(height - 1, iy + 1);

	//确定ix+1,ix-1.iy+1.iy-1的线程

	if (ix < width && iy < height) {
		if (
			src_y[iy_1 * img.step + ix_1] == 0 ||         //(x-1.y-1)
			src_y[iy_1 * img.step + ix] == 0 ||			  //(x,y-1)
			src_y[iy_1 * img.step + ix1] == 0 ||		  //(x+1,y-1)
			src_y[iy * img.step + ix_1] == 0 ||			  //(x-1,y)
			src_y[iy * img.step + ix] == 0 ||			  //(x,y)
			src_y[iy1 * img.step + ix_1] == 0 ||		  //(x-1.y+1)
			src_y[iy1 * img.step + ix] == 0 ||			  //(x,y+1)
			src_y[iy * img.step + ix1] == 0				  //(x+1,y)
			) {
			dst[iy * img.step + ix] = 0;
		}
	}
}

首先对输入的灰度图像二值化,设定自己的阈值,这里设定为130.将图像变成二值图像。

后进行腐蚀。二者的索引方式本质上是相同的,但为了对四周像素值及逆行索引,将ix,iy转成ix-1,ix+1,iy-1,iy+1。其中利用max,min的值,设定前面4个索引不会超出图像边界。

比如第一个像素(0,0)处只有3个相邻的,(x+1,y)(x+1,y+1),(x,y+1),其他5个都是自己本身,其余类推。

2.二值图像的膨胀

膨胀模板算子,中心和周围8个点,如果周围有像素点为255,则中心点为255。全0,才为0。

核函数:

template<int nthreads>
__global__ void compute_kernel(int height, int width, const PtrStepb img, PtrStepb dst) {

	//	1.图像二值化
	const int ix = blockIdx.x * blockDim.x + threadIdx.x;
	const int iy = blockIdx.y * blockDim.y + threadIdx.y;
	const uchar* src_yy = (const uchar*)(img + iy * img.step);
	uchar* dst_yy = (uchar*)(dst + iy * dst.step);

	if (ix < width && iy < height) {
		if (src_yy[ix] >= 130)
			dst_yy[ix] = 255;
		else
			dst_yy[ix] = 0;
	}

	//利用二值图实现图像膨胀
	const uchar* src_y = (const uchar*)(img);
	uchar* dst_y = (uchar*)dst;

	int ix_1 = max(0, ix - 1);
	int ix1 = min(width - 1, ix + 1);
	int iy_1 = max(0,iy - 1);
	int iy1 = min(height - 1, iy + 1);

	//确定ix+1,ix-1.iy+1.iy-1的线程

	if (ix < width && iy < height) {
		if (
			src_y[iy_1 * img.step + ix_1] == 255 ||         //(x-1.y-1)
			src_y[iy_1 * img.step + ix] == 255 ||			  //(x,y-1)
			src_y[iy_1 * img.step + ix1] == 255 ||		  //(x+1,y-1)
			src_y[iy * img.step + ix_1] == 255 ||			  //(x-1,y)
			src_y[iy * img.step + ix] == 255 ||			  //(x,y)
			src_y[iy1 * img.step + ix_1] == 255 ||		  //(x-1.y+1)
			src_y[iy1 * img.step + ix] == 255 ||			  //(x,y+1)
			src_y[iy * img.step + ix1] == 255				  //(x+1,y)
			) {
			dst[iy * img.step + ix] = 255;
		}
	}
}

同理,可以到的膨胀,只不过在判断条件和最后操作上变为255。

看看结果:

1.腐蚀:

2.膨胀

3.灰度图像的腐蚀

灰度图像的腐蚀则是将周围像素值的最小值赋给中心。

核函数:

template<int nthreads>
__global__ void compute_kernel(int height, int width, const PtrStepb img, PtrStepb dst) {

	const int ix = blockIdx.x * blockDim.x + threadIdx.x;
	const int iy = blockIdx.y * blockDim.y + threadIdx.y;

	const uchar* src_y = (const uchar*)(img);
	uchar* dst_y = (uchar*)dst;

	int ix_1 = max(0, ix - 1);
	int ix1 = min(width - 1, ix + 1);
	int iy_1 = max(0,iy - 1);
	int iy1 = min(height - 1, iy + 1);

	//确定ix+1,ix-1.iy+1.iy-1的线程

	if (ix < width && iy < height) {
		if (src_y[iy * img.step + ix] > src_y[iy_1 * img.step + ix_1]) //(x-1,y-1)
			dst_y[iy * img.step + ix] = src_y[iy_1 * img.step + ix_1];
		if (src_y[iy * img.step + ix] > src_y[iy_1 * img.step + ix]) //(x.y-1)
			dst_y[iy * img.step + ix] = src_y[iy_1 * img.step + ix];
		if (src_y[iy * img.step + ix] > src_y[iy_1 * img.step + ix1]) //(x+1.y-1)
			dst_y[iy * img.step + ix] = src_y[iy_1 * img.step + ix1];
		if (src_y[iy * img.step + ix] > src_y[iy * img.step + ix_1])//(x-1,y)
			dst_y[iy * img.step + ix] = src_y[iy * img.step + ix_1];
		if (src_y[iy * img.step + ix] > src_y[iy * img.step + ix1])//(x+1,y)
			dst_y[iy * img.step + ix] = src_y[iy * img.step + ix1];
		if (src_y[iy * img.step + ix] > src_y[iy1 * img.step + ix_1]) //(x-1,y+1)
			dst_y[iy * img.step + ix] = src_y[iy1 * img.step + ix_1];
		if (src_y[iy * img.step + ix] > src_y[iy1 * img.step + ix]) //(x,y+1)
			dst_y[iy * img.step + ix] = src_y[iy1 * img.step + ix];
		if (src_y[iy * img.step + ix] > src_y[iy1 * img.step + ix1]) //(x+1,y+1)
			dst_y[iy * img.step + ix] = src_y[iy1 * img.step + ix1];
	}
}

结果

4.灰度图像的膨胀

与腐蚀相反,找出最大值,赋给中心位置

核函数:

template<int nthreads>
__global__ void compute_kernel(int height, int width, const PtrStepb img, PtrStepb dst) {

	const int ix = blockIdx.x * blockDim.x + threadIdx.x;
	const int iy = blockIdx.y * blockDim.y + threadIdx.y;

	const uchar* src_y = (const uchar*)(img);
	uchar* dst_y = (uchar*)dst;

	int ix_1 = max(0, ix - 1);
	int ix1 = min(width - 1, ix + 1);
	int iy_1 = max(0,iy - 1);
	int iy1 = min(height - 1, iy + 1);

	//确定ix+1,ix-1.iy+1.iy-1的线程

	if (ix < width && iy < height) {
		if (src_y[iy * img.step + ix] <= src_y[iy_1 * img.step + ix_1]) //(x-1,y-1)
			dst_y[iy * img.step + ix] = src_y[iy_1 * img.step + ix_1];
		if (src_y[iy * img.step + ix] <= src_y[iy_1 * img.step + ix]) //(x.y-1)
			dst_y[iy * img.step + ix] = src_y[iy_1 * img.step + ix];
		if (src_y[iy * img.step + ix] <= src_y[iy_1 * img.step + ix1]) //(x+1.y-1)
			dst_y[iy * img.step + ix] = src_y[iy_1 * img.step + ix1];
		if (src_y[iy * img.step + ix] <= src_y[iy * img.step + ix_1])//(x-1,y)
			dst_y[iy * img.step + ix] = src_y[iy * img.step + ix_1];
		if (src_y[iy * img.step + ix] <= src_y[iy * img.step + ix1])//(x+1,y)
			dst_y[iy * img.step + ix] = src_y[iy * img.step + ix1];
		if (src_y[iy * img.step + ix] <= src_y[iy1 * img.step + ix_1]) //(x-1,y+1)
			dst_y[iy * img.step + ix] = src_y[iy1 * img.step + ix_1];
		if (src_y[iy * img.step + ix] <= src_y[iy1 * img.step + ix]) //(x,y+1)
			dst_y[iy * img.step + ix] = src_y[iy1 * img.step + ix];
		if (src_y[iy * img.step + ix] <= src_y[iy1 * img.step + ix1]) //(x+1,y+1)
			dst_y[iy * img.step + ix] = src_y[iy1 * img.step + ix1];
	}
}

结果:

可以看到腐蚀让线条轮廓更细,而膨胀则使得线条轮廓边缘更润滑。

最后给一下,完整代码,只需要替换核函数即可。

#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include<cuda.h>
#include<cuda_device_runtime_api.h>
#include <opencv2/core/cuda.hpp>
#include<opencv2/opencv.hpp>
#include<opencv.hpp>
#include <stdio.h>
#include<iostream>

using namespace std;
using namespace cv;
using namespace cuda;

template<int nthreads>
__global__ void compute_kernel(int height, int width, const PtrStepb img, PtrStepb dst) {

	const int ix = blockIdx.x * blockDim.x + threadIdx.x;
	const int iy = blockIdx.y * blockDim.y + threadIdx.y;

	const uchar* src_y = (const uchar*)(img);
	uchar* dst_y = (uchar*)dst;

	int ix_1 = max(0, ix - 1);
	int ix1 = min(width - 1, ix + 1);
	int iy_1 = max(0,iy - 1);
	int iy1 = min(height - 1, iy + 1);

	//确定ix+1,ix-1.iy+1.iy-1的线程

	if (ix < width && iy < height) {
		if (src_y[iy * img.step + ix] <= src_y[iy_1 * img.step + ix_1]) //(x-1,y-1)
			dst_y[iy * img.step + ix] = src_y[iy_1 * img.step + ix_1];
		if (src_y[iy * img.step + ix] <= src_y[iy_1 * img.step + ix]) //(x.y-1)
			dst_y[iy * img.step + ix] = src_y[iy_1 * img.step + ix];
		if (src_y[iy * img.step + ix] <= src_y[iy_1 * img.step + ix1]) //(x+1.y-1)
			dst_y[iy * img.step + ix] = src_y[iy_1 * img.step + ix1];
		if (src_y[iy * img.step + ix] <= src_y[iy * img.step + ix_1])//(x-1,y)
			dst_y[iy * img.step + ix] = src_y[iy * img.step + ix_1];
		if (src_y[iy * img.step + ix] <= src_y[iy * img.step + ix1])//(x+1,y)
			dst_y[iy * img.step + ix] = src_y[iy * img.step + ix1];
		if (src_y[iy * img.step + ix] <= src_y[iy1 * img.step + ix_1]) //(x-1,y+1)
			dst_y[iy * img.step + ix] = src_y[iy1 * img.step + ix_1];
		if (src_y[iy * img.step + ix] <= src_y[iy1 * img.step + ix]) //(x,y+1)
			dst_y[iy * img.step + ix] = src_y[iy1 * img.step + ix];
		if (src_y[iy * img.step + ix] <= src_y[iy1 * img.step + ix1]) //(x+1,y+1)
			dst_y[iy * img.step + ix] = src_y[iy1 * img.step + ix1];
	}
}

int main() {

	Mat src = imread("C:/Users/1/Pictures/Camera Roll/手枪小姬.jpg");
	cout << " src通道: " << src.channels() << endl;
	Mat a = imread("C:/Users/1/Pictures/Camera Roll/手枪小姬.jpg", 0);
	cout << " a通道: " << a.channels() << endl;
	cout << "a.size():" << a.size() << endl;

	GpuMat d_a(a);
	GpuMat d_dst(a);
	int width = a.size().width;
	int height = a.size().height;

	const int nthreads = 256;
	dim3 bdim(nthreads, 1);
	dim3 gdim(divUp(width, bdim.x), divUp(height, bdim.y));
	compute_kernel<nthreads> << <gdim,bdim >> >(height,width,d_a,d_dst) ;

	Mat dst(d_dst);
	namedWindow("yuan", WINDOW_NORMAL);
	imshow("yuan", src);
	namedWindow("dan", WINDOW_NORMAL);
	imshow("dan", a);
	namedWindow("pengzhang1", WINDOW_NORMAL);
	imshow("pengzhang1", dst);

	waitKey();
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值