生成靶标图像代码——C语言代码实现

1. 生成左右相机拍摄的3个彩色靶标的图像 

两个相机在x轴方向上平移

// 生成左右相机拍摄3个靶标时的图像  生成彩色靶标
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

// 图像尺寸
#define WIDTH 1920
#define HEIGHT 1080

// BMP头信息
#pragma pack(1)
typedef struct {
    unsigned short bfType;       // 文件类型
    unsigned int bfSize;         // 文件大小
    unsigned short bfReserved1;  // 保留字段
    unsigned short bfReserved2;  // 保留字段
    unsigned int bfOffBits;      // 到图像数据的偏移
} BITMAPFILEHEADER;

typedef struct {
    unsigned int biSize;          // DIB头大小
    int biWidth;                  // 图像宽度
    int biHeight;                 // 图像高度
    unsigned short biPlanes;      // 颜色平面数
    unsigned short biBitCount;    // 每个像素的位数
    unsigned int biCompression;   // 压缩类型
    unsigned int biSizeImage;     // 图像大小
    int biXPelsPerMeter;          // 水平分辨率
    int biYPelsPerMeter;          // 垂直分辨率
    unsigned int biClrUsed;       // 颜色表中使用的颜色数
    unsigned int biClrImportant;  // 重要的颜色数
} BITMAPINFOHEADER;

// 3D点结构体
typedef struct {
    float x, y, z;
} Point3D;

// 相机结构体
typedef struct {
    float focal_length;   // 焦距
    float cx, cy;         // 图像中心
} Camera;

// 投影函数,将3D点投影到2D平面
void projectPoint(Camera cam, Point3D pt, int* u, int* v) {
    // 投影公式: u = fx * X / Z + cx, v = fy * Y / Z + cy
    *u = (int)(cam.focal_length * pt.x / pt.z + cam.cx);
    *v = (int)(cam.focal_length * pt.y / pt.z + cam.cy);
}

// 绘制一个圆  生成彩色圆形靶标
void drawCircle(unsigned char* image, int imgWidth, int imgHeight, int x0, int y0, int radius, unsigned char r, unsigned char g, unsigned char b) {
    for (int y = -radius; y <= radius; y++) {
        for (int x = -radius; x <= radius; x++) {
            if (x * x + y * y <= radius * radius) {
                int imgX = x0 + x;
                int imgY = y0 + y;
                if (imgX >= 0 && imgX < imgWidth && imgY >= 0 && imgY < imgHeight) {
                    int index = (imgY * imgWidth + imgX) * 3;
                    image[index + 0] = b; // 蓝色
                    image[index + 1] = g; // 绿色
                    image[index + 2] = r; // 红色
                }
            }
        }
    }
}

// 保存为BMP文件
void saveBMP(const char* filename, unsigned char* image, int width, int height) {
    BITMAPFILEHEADER fileHeader;
    BITMAPINFOHEADER infoHeader;

    fileHeader.bfType = 0x4D42; // "BM"
    fileHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + width * height * 3;
    fileHeader.bfReserved1 = 0;
    fileHeader.bfReserved2 = 0;
    fileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);

    infoHeader.biSize = sizeof(BITMAPINFOHEADER);
    infoHeader.biWidth = width;
    infoHeader.biHeight = height;
    infoHeader.biPlanes = 1;
    infoHeader.biBitCount = 24;
    infoHeader.biCompression = 0;
    infoHeader.biSizeImage = width * height * 3;
    infoHeader.biXPelsPerMeter = 0;
    infoHeader.biYPelsPerMeter = 0;
    infoHeader.biClrUsed = 0;
    infoHeader.biClrImportant = 0;

    FILE* file = fopen(filename, "wb");
    fwrite(&fileHeader, sizeof(BITMAPFILEHEADER), 1, file);
    fwrite(&infoHeader, sizeof(BITMAPINFOHEADER), 1, file);
    fwrite(image, 3, width * height, file);
    fclose(file);
}

int main() {
    // 创建空白图像(黑色背景)
    unsigned char* imageLeft = (unsigned char*)calloc(WIDTH * HEIGHT * 3, sizeof(unsigned char));
    unsigned char* imageRight = (unsigned char*)calloc(WIDTH * HEIGHT * 3, sizeof(unsigned char));

    // 定义相机参数
    Camera leftCam = { 1000.0f, WIDTH / 2.0f, HEIGHT / 2.0f };  // 左相机
    Camera rightCam = { 1000.0f, WIDTH / 2.0f, HEIGHT / 2.0f }; // 右相机(假设右相机位置平移)

    // 定义3个圆形靶标的3D坐标
    Point3D targets[3] = {
        { 0, 0, 100 },
        { 10, 10, 120 },
        { -10, -10, 110 }
    };

    // 投影靶标到左相机的图像平面
    for (int i = 0; i < 3; i++) {
        int u, v;
        projectPoint(leftCam, targets[i], &u, &v);
        drawCircle(imageLeft, WIDTH, HEIGHT, u, v, 50, 255, 0, 0); // 在左图像上绘制红色靶标
    }

    // 投影靶标到右相机的图像平面(假设右相机沿X轴平移)
    for (int i = 0; i < 3; i++) {
        int u, v;
        targets[i].x -= 20; // 模拟右相机的平移
        projectPoint(rightCam, targets[i], &u, &v);
        drawCircle(imageRight, WIDTH, HEIGHT, u, v, 50, 0, 255, 0); // 在右图像上绘制绿色靶标
    }

    // 保存为BMP图像
    saveBMP("left_camera.bmp", imageLeft, WIDTH, HEIGHT);
    saveBMP("right_camera.bmp", imageRight, WIDTH, HEIGHT);

    // 释放内存
    free(imageLeft);
    free(imageRight);

    printf("保存成功!\n");
    return 0;
}

生成图像如下(左相机图像+右相机图像): 

 如果想要生成白色靶标只需要将,R、G、B分量的参数改为255即可,代码如下:

void drawCircle(unsigned char* image, int imgWidth, int imgHeight, int x0, int y0, int radius) {
    for (int y = -radius; y <= radius; y++) {
        for (int x = -radius; x <= radius; x++) {
            if (x * x + y * y <= radius * radius) {
                int imgX = x0 + x;
                int imgY = y0 + y;
                if (imgX >= 0 && imgX < imgWidth && imgY >= 0 && imgY < imgHeight) {
                    int index = (imgY * imgWidth + imgX) * 3;
                    image[index + 0] = 255; // 蓝色分量(255表示白色)
                    image[index + 1] = 255; // 绿色分量
                    image[index + 2] = 255; // 红色分量
                }
            }
        }
    }
}

 生成图像如下(左相机图像+右相机图像):

2. 生成4个白色靶标,其余部分为黑色背景

每张图像中包含两个靶标,第一组左右相机拍摄的图像包含靶标1和2,第二组包含靶标3和4。同时输出生成靶标的位置。

// 生成左右两个相机拍摄的两张靶标图像 每张图像中有2个挨着的圆形靶标
// 左右相机第一张图像对应靶标1和2 第二张图像对应靶标3和4
// 左相机图像1 靶标1坐标: (960, 540)
// 左相机图像1 靶标2坐标 : (1043, 623)
// 左相机图像2 靶标3坐标 : (869, 449)
// 左相机图像2 靶标4坐标 : (1113, 386)
// 右相机图像1 靶标1坐标 : (760, 540)
// 右相机图像1 靶标2坐标 : (876, 623)
// 右相机图像2 靶标3坐标 : (687, 449)
// 右相机图像2 靶标4坐标 : (960, 386)
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

// 图像尺寸
#define WIDTH 1920
#define HEIGHT 1080

// BMP头信息
#pragma pack(1)
typedef struct {
    unsigned short bfType;       // 文件类型
    unsigned int bfSize;         // 文件大小
    unsigned short bfReserved1;  // 保留字段
    unsigned short bfReserved2;  // 保留字段
    unsigned int bfOffBits;      // 到图像数据的偏移
} BITMAPFILEHEADER;

typedef struct {
    unsigned int biSize;          // DIB头大小
    int biWidth;                  // 图像宽度
    int biHeight;                 // 图像高度
    unsigned short biPlanes;      // 颜色平面数
    unsigned short biBitCount;    // 每个像素的位数
    unsigned int biCompression;   // 压缩类型
    unsigned int biSizeImage;     // 图像大小
    int biXPelsPerMeter;          // 水平分辨率
    int biYPelsPerMeter;          // 垂直分辨率
    unsigned int biClrUsed;       // 颜色表中使用的颜色数
    unsigned int biClrImportant;  // 重要的颜色数
} BITMAPINFOHEADER;

// 3D点结构体
typedef struct {
    float x, y, z;
} Point3D;

// 相机结构体
typedef struct {
    float focal_length;   // 焦距
    float cx, cy;         // 图像中心
} Camera;

// 投影函数,将3D点投影到2D平面
void projectPoint(Camera cam, Point3D pt, int* u, int* v) {
    *u = (int)(cam.focal_length * pt.x / pt.z + cam.cx);
    *v = (int)(cam.focal_length * pt.y / pt.z + cam.cy);
}

// 绘制一个圆
void drawCircle(unsigned char* image, int imgWidth, int imgHeight, int x0, int y0, int radius) {
    for (int y = -radius; y <= radius; y++) {
        for (int x = -radius; x <= radius; x++) {
            if (x * x + y * y <= radius * radius) {
                int imgX = x0 + x;
                int imgY = y0 + y;
                if (imgX >= 0 && imgX < imgWidth && imgY >= 0 && imgY < imgHeight) {
                    int index = (imgY * imgWidth + imgX) * 3;
                    image[index + 0] = 255; // 蓝色分量(255表示白色)
                    image[index + 1] = 255; // 绿色分量
                    image[index + 2] = 255; // 红色分量
                }
            }
        }
    }
}

// 保存为BMP文件
void saveBMP(const char* filename, unsigned char* image, int width, int height) {
    BITMAPFILEHEADER fileHeader;
    BITMAPINFOHEADER infoHeader;

    fileHeader.bfType = 0x4D42; // "BM"
    fileHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + width * height * 3;
    fileHeader.bfReserved1 = 0;
    fileHeader.bfReserved2 = 0;
    fileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);

    infoHeader.biSize = sizeof(BITMAPINFOHEADER);
    infoHeader.biWidth = width;
    infoHeader.biHeight = height;
    infoHeader.biPlanes = 1;
    infoHeader.biBitCount = 24;
    infoHeader.biCompression = 0;
    infoHeader.biSizeImage = width * height * 3;
    infoHeader.biXPelsPerMeter = 0;
    infoHeader.biYPelsPerMeter = 0;
    infoHeader.biClrUsed = 0;
    infoHeader.biClrImportant = 0;

    FILE* file = fopen(filename, "wb");
    fwrite(&fileHeader, sizeof(BITMAPFILEHEADER), 1, file);
    fwrite(&infoHeader, sizeof(BITMAPINFOHEADER), 1, file);
    fwrite(image, 3, width * height, file);
    fclose(file);
}

int main() {
    // 创建空白图像(黑色背景)
    unsigned char* imageLeft1 = (unsigned char*)calloc(WIDTH * HEIGHT * 3, sizeof(unsigned char));
    unsigned char* imageLeft2 = (unsigned char*)calloc(WIDTH * HEIGHT * 3, sizeof(unsigned char));
    unsigned char* imageRight1 = (unsigned char*)calloc(WIDTH * HEIGHT * 3, sizeof(unsigned char));
    unsigned char* imageRight2 = (unsigned char*)calloc(WIDTH * HEIGHT * 3, sizeof(unsigned char));

    // 定义相机参数
    Camera leftCam = { 1000.0f, WIDTH / 2.0f, HEIGHT / 2.0f };  // 左相机
    Camera rightCam = { 1000.0f, WIDTH / 2.0f, HEIGHT / 2.0f }; // 右相机

    // 定义4个圆形靶标的3D坐标
    Point3D targets[4] = {
        { 0, 0, 100 },     // 靶标1
        { 10, 10, 120 },   // 靶标2
        { -10, -10, 110 }, // 靶标3
        { 20, -20, 130 }   // 靶标4
    };

    // 左相机图像1:靶标1和靶标2
    for (int i = 0; i < 2; i++) {
        int u, v;
        projectPoint(leftCam, targets[i], &u, &v);
        drawCircle(imageLeft1, WIDTH, HEIGHT, u, v, 50); // 在左图像上绘制白色靶标
        printf("左相机图像1 靶标%d坐标: (%d, %d)\n", i + 1, u, v); // 输出坐标
    }

    // 左相机图像2:靶标3和靶标4
    for (int i = 2; i < 4; i++) {
        int u, v;
        projectPoint(leftCam, targets[i], &u, &v);
        drawCircle(imageLeft2, WIDTH, HEIGHT, u, v, 50); // 在左图像上绘制白色靶标
        printf("左相机图像2 靶标%d坐标: (%d, %d)\n", i + 1, u, v); // 输出坐标
    }

    // 右相机图像1:靶标1和靶标2(右相机平移X轴)
    for (int i = 0; i < 2; i++) {
        int u, v;
        Point3D shiftedTarget = targets[i];  // 拷贝原始坐标
        shiftedTarget.x -= 20; // 模拟右相机平移
        projectPoint(rightCam, shiftedTarget, &u, &v);
        drawCircle(imageRight1, WIDTH, HEIGHT, u, v, 50); // 在右图像上绘制白色靶标
        printf("右相机图像1 靶标%d坐标: (%d, %d)\n", i + 1, u, v); // 输出坐标
    }

    // 右相机图像2:靶标3和靶标4
    for (int i = 2; i < 4; i++) {
        int u, v;
        Point3D shiftedTarget = targets[i];  // 拷贝原始坐标
        shiftedTarget.x -= 20; // 模拟右相机平移
        projectPoint(rightCam, shiftedTarget, &u, &v);
        drawCircle(imageRight2, WIDTH, HEIGHT, u, v, 50); // 在右图像上绘制白色靶标
        printf("右相机图像2 靶标%d坐标: (%d, %d)\n", i + 1, u, v); // 输出坐标
    }

    // 保存为BMP图像
    saveBMP("left_camera1.bmp", imageLeft1, WIDTH, HEIGHT);
    saveBMP("left_camera2.bmp", imageLeft2, WIDTH, HEIGHT);
    saveBMP("right_camera1.bmp", imageRight1, WIDTH, HEIGHT);
    saveBMP("right_camera2.bmp", imageRight2, WIDTH, HEIGHT);

    // 释放内存
    free(imageLeft1);
    free(imageLeft2);
    free(imageRight1);
    free(imageRight2);

    printf("图像保存成功!\n");
    return 0;
}

图像如下所示(依次是left_camera1.bmp,left_camera2.bmp,right_camera1.bmp,right_camera1.bmp): 

 

以下是圆形非对称靶标相机标定的Python代码代码中有详细的注释说明: ```python import numpy as np import cv2 # 定义圆形非对称靶标的行列数和每个小格子的大小 rows = 6 cols = 9 square_size = 20 # 单位为毫米 # 生成标定板角点的世界坐标系坐标 objp = np.zeros((rows * cols, 3), np.float32) objp[:, :2] = np.mgrid[0:cols, 0:rows].T.reshape(-1, 2) * square_size # 存储所有的角点坐标 objpoints = [] # 世界坐标系中的坐标 imgpoints = [] # 图像坐标系中的坐标 # 读取所有标定图片并提取角点坐标 images = glob.glob('calibration_images/*.jpg') for fname in images: img = cv2.imread(fname) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 查找角点 ret, corners = cv2.findCirclesGrid(gray, (cols, rows), flags=cv2.CALIB_CB_ASYMMETRIC_GRID) # 如果找到了角点,则添加到objpoints和imgpoints中 if ret == True: objpoints.append(objp) imgpoints.append(corners) # 在图像上绘制角点 cv2.drawChessboardCorners(img, (cols, rows), corners, ret) cv2.imshow('img', img) cv2.waitKey(500) cv2.destroyAllWindows() # 进行相机标定 ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None) # 打印标定结果 print("相机内参矩阵:\n", mtx) print("畸变系数:\n", dist) # 校正图像 img = cv2.imread('calibration_images/test_image.jpg') h, w = img.shape[:2] newcameramtx, roi = cv2.getOptimalNewCameraMatrix(mtx, dist, (w, h), 1, (w, h)) dst = cv2.undistort(img, mtx, dist, None, newcameramtx) # 显示校正前后的图像 cv2.imshow('original', img) cv2.imshow('corrected', dst) cv2.waitKey(0) cv2.destroyAllWindows() ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值