使用cuda绘制直线

1. 判断点是否在直线上

__device__ int isInsideLine(int startX, int startY, int endX, int endY, int lineWidth, int x, int y)
{
    
    
	// Calculate squared length of line segment
	float len2 = powf(endY - startY, 2) + powf(endX - startX, 2);
	// Calculate dot product of vectors
	float dot = (x - startX) * (endX - startX) + (y - startY) * (endY - startY);
	// Check if point is beyond starting point or ending point of line segment
	if (dot < 0 || dot > len2) {
    
    
		return 0;
	}
	// Calculate distance between point and line
	float dist = abs((endY - startY) * x - (endX - startX) * y + endX * startY - endY * startX) / sqrtf(len2);
	// Check if distance is less than half the line width
	return (dist < lineWidth / 2.0f);
}

这是一个用于判断点是否在直线上的函数。函数接受起点坐标(startX, startY)、终点坐标(endX, endY)、线宽(lineWidth)、以及要判断的点坐标(x, y)作为参数。函数返回一个整数值,如果点在直线上,则返回1,否则返回0。

函数的实现过程如下:

  1. 计算线段的长度的平方(len2),使用powf函数计算。
  2. 计算向量的点积(dot),使用(x - startX) * (endX - startX) + (y - startY) * (endY - startY)计算。
  3. 检查点是否在线段的起点和终点之外,即dot < 0或dot > len2,则返回0。
  4. 计算点到直线的距离(dist),使用abs((endY - startY) * x - (endX - startX) * y + endX * startY - endY * startX) / sqrtf(len2)计算。
  5. 检查距离是否小于线宽的一半(lineWidth / 2.0f),如果是,则返回1,否则返回0。

2. cuda画线核函数

__global__ void drawLineKernel(cv::cuda::PtrStep<uchar> nv12Data, int nv12Pitch, int width, int height, TyPoint start, TyPoint end, int thickness, uchar Y, uchar U, uchar V)
{
    
    
	int x = blockIdx.x * blockDim.x + threadIdx.x;
	int y = blockIdx.y * blockDim.y + threadIdx.y;
	if (x < width && y < height)
	{
    
    
		int yIndex = y * nv12Pitch + x;
		int uvIndex = (y / 2) * nv12Pitch + (x / 2) * 2;
		int startYIdx = start.y * nv12Pitch + start.x;
		int endYIdx = end.y * nv12Pitch + end.x;
		
		if (isInsideLine(start.x, start.y, end.x, end.y, thickness, x, y))
		{
    
    
			nv12Data.data[yIndex] = Y;
			nv12Data.data[(uvIndex + nv12Pitch * height)] = U;
			nv12Data.data[(uvIndex + nv12Pitch * height + 1)] = V;
		}
	}
}

这是一个用于在CUDA中绘制直线的内核函数。函数接受一个NV12格式的图像数据(nv12Data)、图像数据的行字节数(nv12Pitch)、图像的宽度(width)和高度(height)、起点坐标(start)、终点坐标(end)、线宽(thickness)以及颜色(Y、U、V)作为参数。

函数的实现过程如下:

  1. 计算当前线程在图像中的坐标(x, y),使用blockIdx和threadIdx计算。
  2. 检查当前坐标是否在图像范围内,如果在范围内则继续执行,否则跳过。
  3. 计算当前像素在Y分量数组中的索引(yIndex)和在UV分量数组中的索引(uvIndex)。
  4. 计算起点和终点在Y分量数组中的索引(startYIdx和endYIdx)。
  5. 调用isInsideLine函数判断当前像素是否在直线内部,如果是则继续执行,否则跳过。
  6. 将颜色值(Y、U、V)写入对应的像素位置。

3. 调用核函数绘制直线

void RGBtoYUV(unsigned char R, unsigned char G, unsigned char B, int& Y, int& U, int& V) {
    
    
		Y = 0.2126 * R + 0.7152 * G + 0.0722 * B;
		U = -0.1146 * R - 0.3854 * G + 0.5000 * B + 128;
		V = 0.5000 * R - 0.4542 * G - 0.0458 * B + 128;
}

void drawLine(cv::cuda::GpuMat& nv12Frame, TyPoint start, TyPoint end, int thickness, cv::Scalar color)
	{
    
    
		int Y = 0, U = 0, V = 0;
		RGBtoYUV(color[2], color[1], color[0], Y, U, V);

		const dim3 block(32, 16);
		const dim3 grid(divUp(nv12Frame.cols, block.x), divUp(nv12Frame.rows, block.y));
		
		drawLineKernel << <grid, block>> > (nv12Frame, nv12Frame.step, nv12Frame.cols, nv12Frame.rows/3*2, start, end, thickness, (uchar)Y, (uchar)U, (uchar)V);
		
		cudaThreadSynchronize();
	}

猜你喜欢

转载自blog.csdn.net/wyw0000/article/details/131508541