使用Bresenham算法计算直线上的所有像素点。
Bresenham算法是一种用于在离散网格上绘制直线的算法。它是由美国计算机科学家Jack E. Bresenham于1962年提出的。
该算法的基本思想是从起始点开始,以最小的步长沿着直线绘制像素。以直线斜率的绝对值小于等于1为例,算法通过在x方向上递增一个固定的步长,并在y方向上根据直线斜率进行适当的调整来绘制像素。
具体步骤如下:
std::vector<cv::Point> calculatePixelsOnLine(cv::Point start, cv::Point end, int lineWidth)
{
std::vector<cv::Point> pixels;
int dx = std::abs(end.x - start.x);
int dy = std::abs(end.y - start.y);
int sx = (start.x < end.x) ? 1 : -1;
int sy = (start.y < end.y) ? 1 : -1;
int err = dx - dy;
while (true) {
for (int i = -lineWidth / 2; i <= lineWidth / 2; i++) {
for (int j = -lineWidth / 2; j <= lineWidth / 2; j++) {
cv::Point pixel = { start.x + i, start.y + j };
pixels.push_back(pixel);
}
}
if (start.x == end.x && start.y == end.y) {
break;
}
int e2 = 2 * err;
if (e2 > -dy) {
err -= dy;
start.x += sx;
}
if (e2 < dx) {
err += dx;
start.y += sy;
}
}
return pixels;
}
Bresenham算法的优点是使用了整数运算,避免了浮点运算,从而提高了计算效率。它适用于在离散网格上绘制直线,如计算机图形学中的像素绘制、线段绘制等应用场景。
__global__ void drawLineOnImage(cv::cuda::PtrStep<uchar> nv12Data, int nv12Pitch, int imageWidth, int imageHeight, int* linePixels, int numPixels, uchar Y, uchar U, uchar V) {
int index = blockIdx.x * blockDim.x + threadIdx.x;
if (index < numPixels) {
int x = linePixels[index * 2];
int y = linePixels[index * 2 + 1];
// 计算图像数组中对应的索引
int imageIndex = y * nv12Pitch + x;
// 直接在图像数组中写入像素值
nv12Data.data[imageIndex] = Y;
// 在UV分量中写入像素值
int uvImageWidth = nv12Pitch / 2;
int uvImageHeight = imageHeight / 2;
int uvIndex = (y >> 1) * nv12Pitch + (x >> 1) * 2;
nv12Data.data[nv12Pitch * imageHeight + uvIndex] = U;
nv12Data.data[nv12Pitch * imageHeight + uvIndex + 1] = V;
}
}
#include
#include "cuda_runtime.h"
using namespace cv;
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);
vector<cv::Point> linePixels = typonteq::AIUtils::calculatePixelsOnLine({ start.x, start.y }, { end.x, end.y }, thickness);
int numPixels = linePixels.size();
// 定义CUDA核函数的块大小和网格大小
int blockSize = 256;
int numBlocks = (numPixels + blockSize - 1) / blockSize;
if (!cudaStream) {
cudaSafeCall(cudaStreamCreate(&cudaStream));
}
int* d_linePixels;
cudaMalloc((void**)&d_linePixels, linePixels.size() * 2 * sizeof(int));
cudaMemcpy(d_linePixels, linePixels.data(), linePixels.size() * 2 * sizeof(int), cudaMemcpyHostToDevice);
drawLineOnImage << <numBlocks, blockSize, 0, cudaStream >> > (nv12Frame, nv12Frame.step, nv12Frame.cols, nv12Frame.rows / 3 * 2, d_linePixels, numPixels, (uchar)Y, (uchar)U, (uchar)V);
int ret = cudaGetLastError();
if (ret != cudaSuccess) {
printf("%s cudaGetLastError:%d\n", __FUNCTION__, ret);
}
if (!cudaStream)
cudaSafeCall(cudaStreamSynchronize(cudaStream));
// 释放设备内存
cudaFree(d_linePixels);
}
注意:这里输入image为nv12格式