Nvidia Video Codec SDK——AppDecImageProvider动态模糊

Nvidia Video Codec SDK——AppDecImageProvider动态模糊

Cpp文件

初始化变量:
在这里插入图片描述
平滑函数Bgra32ToSmooth,注意f和deep都转化为指针类型,因为数据在显存读取:

Bgra32ToSmooth((uint8_t *)ppFrame_Deep[i],(uint8_t*)pTmpImage,(uint8_t*)sTmpImage, 4 * dec.GetWidth(), dec.GetWidth(), dec.GetHeight(), x_position, y_position, v, d, (float *)f, far_distance, near_distance, (int *)deep);

cu文件

void Bgra32ToSmooth(uint8_t *yuvDeep, uint8_t *dpBgra, uint8_t *smoothBgra,  int nBgraPitch, int nWidth, int nHeight, int x_position, int y_position,float v,float d, float *f, int far_distance, int near_distance, int *deep) {
	focalLength <<<1, 1 >>> (yuvDeep, x_position, y_position, v, f, far_distance, near_distance, deep, nWidth);
	Bgra32ToSmoothKernel
		<<<dim3((nWidth + 127) / 128, (nHeight + 7) / 8), dim3(128, 8)>>>
		(yuvDeep, dpBgra, smoothBgra, x_position, y_position, nBgraPitch, nWidth, nHeight, f, d, far_distance, near_distance, deep);
}

核函数focalLength——获得注视点对应深度

focalLength <<<1, 1 >>> (yuvDeep, x_position, y_position, v, f, far_distance, near_distance, deep, nWidth);
__global__ static void focalLength(uint8_t *yuvDeep, int x_position, int y_position, float v, float *f, int far_distance, int near_distance, int *deep,int nWidth) {
	*deep = (far_distance*near_distance) / (near_distance + (far_distance - near_distance)*yuvDeep[x_position + y_position*nWidth]/255.0f);
	*f = *deep * v / (*deep + v);
}

核函数Bgra32ToSmooth

Bgra32ToSmoothKernel
	<<<dim3((nWidth + 127) / 128, (nHeight + 7) / 8), dim3(128, 8)>>>
	(yuvDeep, dpBgra, smoothBgra, x_position, y_position, nBgraPitch, nWidth, nHeight, f, d, far_distance, near_distance, deep);
__global__ static void Bgra32ToSmoothKernel(uint8_t *yuvDeep,uint8_t *pRgb, uint8_t *sRgb, int x_position, int y_position, int nBgraPitch, int nWidth, int nHeight, float *f, float d, int far_distance, int near_distance,int *depth) {
	int x = threadIdx.x + blockIdx.x * blockDim.x;//宽方向
	int y = threadIdx.y + blockIdx.y * blockDim.y;//高方向
	if (x + 1 >= nWidth || y + 1 >= nHeight) {
		return;
	}
	int Index = x * 4 + y * nBgraPitch;//当前像素点的位置
	sRgb[Index]  = pRgb[Index];
	sRgb[Index + 1] = pRgb[Index + 1];
	sRgb[Index + 2] = pRgb[Index + 1];
	sRgb[Index + 3] = pRgb[Index + 3];
	//缩放因子,距离时乘以缩放因子,弥散圆时除以缩放因子
	float alpha = cos(asin(abs(y - nHeight / 2) / (float)(nWidth / 4)));//距离缩放因子,越靠近南北极点值越小(该距离是以二维纹理距离为基准的,基线为纹理中心水平线,因此alpha<=1)
	float dist = dis(x, y, x_position, y_position, nWidth, alpha);//当前计算像素点与注视点的距离
	int currentDepth = (far_distance*near_distance) / (near_distance + (far_distance - near_distance)*yuvDeep[x + y*nWidth] / 255.0);//计算当前像素点的深度值
	float blurCircle = getRadius(currentDepth, depth, f, d) / (alpha < 0.1 ? 0.1 : alpha) * 300;//计算弥散圆半径,返回blurCiecle最大值在0.067左右,因此乘以一个放大因子
	float radius = sqrtf(dist * dist + blurCircle * blurCircle);
	unsigned int sum_r = 0, sum_g = 0, sum_b = 0, count = 0;
	int rightUp = 0, leftUp = 0, rightLow = 0, leftLow = 0;
	for (int m = 0; m < radius; m++) {
		for (int n = 0; n < radius; n++) {
			rightUp = rightUpIndex(x + m, y + n, nWidth, nHeight, nBgraPitch);
			leftUp = leftUpIndex(x - m, y + n, nWidth, nHeight, nBgraPitch);
			rightLow = rightLowIndex(x + m, y - n, nWidth, nHeight, nBgraPitch);
			leftLow = leftLowIndex(x - m, y - n, nWidth, nHeight, nBgraPitch);
			sum_r = sum_r + pRgb[rightUp] + pRgb[leftUp] + pRgb[rightLow] + pRgb[leftLow];
			sum_g = sum_g + pRgb[rightUp + 1] + pRgb[leftUp + 1] + pRgb[rightLow + 1] + pRgb[leftLow + 1];
			sum_b = sum_b + pRgb[rightUp + 2] + pRgb[leftUp + 2] + pRgb[rightLow + 2] + pRgb[leftLow + 2];
			count += 4;
		}
	}
	sum_r = average_color(sum_r, count);
	sum_g = average_color(sum_g, count);
	sum_b = average_color(sum_b, count);
	if (sum_r != 0 || sum_g != 0 || sum_b != 0) {  //如果sum均为0,则radius=0,保持原来的值不变
		sRgb[x * 4 + y * nBgraPitch] = (uint8_t)sum_r;
		sRgb[x * 4 + y * nBgraPitch + 1] = (uint8_t)sum_g;
		sRgb[x * 4 + y * nBgraPitch + 2] = (uint8_t)sum_b;
	}
	//printf("radius = %f, ", radius);
	//printf("%d, ",yuvDeep[x + y * nWidth]);
}

其中各函数如下:
计算各像素点之间的距离dis函数

__device__ float dis(int x,int y,int x_position, int y_position, int width, float alpha){
	int x_dis =alpha * (abs(x - x_position) < width/2 ? abs(x - x_position) : width - abs(x - x_position));
	return sqrtf((x_dis)*(x_dis) + (y - y_position)*(y - y_position))/100;
}

计算弥散圆直径getRadius函数

__device__ inline float getRadius(int currentDepth, int *depth, float *f, float d){
	return (currentDepth - *depth) > 0 ? f[0]*d*(currentDepth - *depth) / (*depth*currentDepth) : f[0]*d*(*depth - currentDepth) / (*depth*currentDepth);
}

沿各方向搜索,确定像素点跳变函数

__device__  int rightUpIndex(int x, int y, int width, int height, int nBgraPitch) {
	x = (x >= width ? x - width : x);//如果x超出边界则取到的点为x-width
	if (y >= height) {  //如果y超出边界,不仅y值会改变,x也会改变
		y = 2 * height - y - 1;
		x = width - x;
	}
	return x * 4 + y*nBgraPitch;
}
__device__  int leftUpIndex(int x, int y, int width, int height, int nBgraPitch){
	x = (x < 0 ? x + width : x);
	if (y >= height) {
		y = 2 * height - y - 1;
		x = width - x;
	}
	return x * 4 + y*nBgraPitch;
}
__device__  int rightLowIndex(int x, int y, int width, int height, int nBgraPitch) {
	x = (x >= width ? x - width : x);
	if (y < 0) {
		y = -y;
		x = width - x;
	}
	return x * 4 + y*nBgraPitch;
}
__device__  int leftLowIndex(int x, int y, int width, int height, int nBgraPitch) {
	x = (x < 0 ? x + width : x);
	if (y < 0) {
		y = -y;
		x = width - x;
	}
	return x * 4 + y*nBgraPitch;
}
__device__ inline int average_color(int sum,int count){
	return count == 0 ? sum : (sum / count);
}

    注意在x方向存在的跳变只与x有关,当搜索x大于width或小于0时,对应的像素点变为(x+width)%width
    在y方向存在的跳变不仅与y有关,还与x有关。当y大于height时,y变为2 * height - y - 1;当y小于0时,y变为-y。当y发生跳变时,x变为width-x,即x跳变后的点与跳变前的点关于x=width/2对称。
缩放因子alpha:

float alpha = cos(asin(abs(y - nHeight / 2) / (float)(nWidth / 4)));

在南北极方向,x轴存在较大畸变:
    对于小凹成像特性,南北极点的畸变导致在球体上离得十分近的两点,由于畸变原因,映射回二维纹理时可能离得非常远,由于我们计算距离时是按照二维纹理上各像素点的距离计算的,因此distance要乘以alpha。
    对于深度差与模糊度的关系,由于我们计算的弥散圆直径实际是计算的球体上的弥散圆直径(现实生活中观察的场景相当于观察球体上的纹理),而最终计算的时候是按照二维纹理上的弥散圆计算的,因此导致在南北极点球体上弥散圆包含了大量的点,而二维纹理上计算弥散圆时只包含了少量的点。因此弥散圆直径radius要除以alpha。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值