Draw a straight line using cuda

1. Determine whether the point is on a straight line

__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);
}

This is a function used to determine whether a point is on a straight line. The function accepts starting point coordinates (startX, startY), end point coordinates (endX, endY), line width (lineWidth), and point coordinates to be judged (x, y) as parameters. The function returns an integer value, 1 if the point is on the line, and 0 otherwise.

The implementation process of the function is as follows:

  1. Calculate the square of the length of the line segment (len2), using the powf function to calculate.
  2. Computes the dot product (dot) of vectors, calculated using (x - startX) * (endX - startX) + (y - startY) * (endY - startY).
  3. Returns 0 if the check point is outside the start and end of the line segment, i.e. dot < 0 or dot > len2.
  4. Calculate the distance (dist) from the point to the line, using abs((endY - startY) * x - (endX - startX) * y + endX * startY - endY * startX) / sqrtf(len2) calculation.
  5. Checks if the distance is less than half the line width (lineWidth / 2.0f) and returns 1 if it is, 0 otherwise.

2. cuda line drawing kernel function

__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;
		}
	}
}

This is a kernel function for drawing straight lines in CUDA. The function accepts an image data in NV12 format (nv12Data), the number of rows of image data (nv12Pitch), the width (width) and height (height) of the image, the starting point coordinates (start), the end point coordinates (end), the line width ( thickness) and color (Y, U, V) as parameters.

The implementation process of the function is as follows:

  1. Calculate the coordinates (x, y) of the current thread in the image, using blockIdx and threadIdx to calculate.
  2. Check if the current coordinates are within the range of the image, if so, continue, otherwise skip.
  3. Calculate the index (yIndex) of the current pixel in the Y component array and the index (uvIndex) in the UV component array.
  4. Computes the indices of the start and end points in the Y component array (startYIdx and endYIdx).
  5. Call the isInsideLine function to judge whether the current pixel is inside the line, if so, continue to execute, otherwise skip.
  6. Write the color value (Y, U, V) to the corresponding pixel location.

3. Call the kernel function to draw a straight line

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();
	}

Guess you like

Origin blog.csdn.net/wyw0000/article/details/131508541