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

news2024/12/26 14:10:54
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): 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2180167.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

掌握自动化测试必要的几种技能?

1.自动化测试员技能——编程语言 当我开始担任手动测试人员时&#xff0c;我不喜欢编码。但是&#xff0c;当我逐渐进入自动化领域时&#xff0c;对我来说很清楚&#xff0c;如果没有对编程语言的一些基本了解&#xff0c;就无法编写逻辑自动化测试脚本。 对编程有一点了解&a…

短视频矩阵源码oem/矩阵系统搭建/源码开发注意事项知识分享

短视频矩阵系统的源码框架主要涵盖Spring、Struts与Hibernate三种。Spring是一款全栈式Java应用开发框架&#xff0c;集成了IOC容器、AOP以及事务管理等关键功能。Struts则基于MVC架构设计&#xff0c;用于Web应用程序的开发&#xff0c;有效分离数据模型、用户界面及控制器逻辑…

全面指南:探索并实施解决Windows系统中“mfc140u.dll丢失”的解决方法

当你的电脑出现mfc140u.dll丢失的问题是什么情况呢&#xff1f;mfc140u.dll文件依赖了什么&#xff1f;mfc140u.dll丢失会导致电脑出现什么情况&#xff1f;今天这篇文章就和大家聊聊mfc140u.dll丢失的解决办法。希望能够有效的帮助你解决这问题。 哪些程序依赖mfc140u.dll文件…

深圳市软件行业协会领导到访开源网安,共筑大湾区数字经济安全未来

近日&#xff0c;深圳市软件行业协会会长邓爱国、秘书长郑飞等一行人到访开源网安进行参观交流。双方以网信行业技能培训、软件安全开发能力评价和智能网联汽车安全测试等方面为探讨方向&#xff0c;对未来的合作进行了深入交流。 在参观过后&#xff0c;深圳市软件行业协会相关…

查找满足条件的行序号

有 2022 年 1 月的日销售额统计表如下所示&#xff1a; 找出日销售额大于 1000 的日子&#xff1a; spl("E(?1).pselecta(Sales>1000)",A1:B32)pselecta()返回所有满足条件的记录序号&#xff0c;pselect() 则只返回第一个满足条件的行序号 免费课程、免费软件下…

Elasticsearch要点简记

Elasticsearch要点简记 1、ES概述2、基础概念&#xff08;1&#xff09;索引、文档、字段&#xff08;2&#xff09;映射&#xff08;3&#xff09;DSL 3、架构原理4、索引字段的数据类型5、ES的三种分页方式&#xff08;1&#xff09;深度分页&#xff08;fromsize&#xff09…

码随想录算法训练营第60天|卡码网:94. 城市间货物运输 I、95. 城市间货物运输 II、96. 城市间货物运输 III

1.卡码网&#xff1a;94. 城市间货物运输 I 题目链接&#xff1a;https://kamacoder.com/problempage.php?pid1152 文章链接&#xff1a;https://www.programmercarl.com/kamacoder/0094.城市间货物运输I-SPFA.html 思路&#xff1a; 只对 上一次松弛的时候更新过的节点作为出…

智能餐饮:Spring Boot 点餐系统

第四章 系统设计 4.1 系统体系结构 网上点餐系统的结构图4-1所示&#xff1a; 图4-1 系统结构 模块包括主界面&#xff0c;首页、个人中心、用户管理、美食店管理、美食分类管理、美食信息管理、美食订单管理、美食评价管理、系统管理等进行相应的操作。 登录系统结构图&…

2025年3月PMP考试《PMBOK®指南》第六版不再作为参考资料

大家都知道《PMBOK指南》第六版是PMP认证考试的必备教材&#xff0c;由项目管理协会&#xff08;PMI&#xff09;指定。本书详细介绍了项目管理的5个过程组&#xff0c;并对项目管理的10个知识领域进行了阐述。 就在2024.9.30昨天的时候中国国际人才交流基金会公布了&#xff…

崖山数据库的共享集群机制初探

本文作者&#xff1a;YashanDB高级服务工程师周国超 YashanDB共享集群是崖⼭数据库系统&#xff08;YashanDB&#xff09;的⼀个关键特性&#xff0c;它是⼀个单库多实例的多活数据库系统。⽤⼾可以连接到任意实例访问同⼀个数据库&#xff0c;多个数据库实例能够并发读写同⼀…

QT对QBytearray的data()指针进行结构体转换时会自动字节对齐填充

1、测试代码 #include <QCoreApplication>#pragma pack(push, 1) typedef struct {int a;float b;char c;int *d; }testStruct; #pragma pack(pop)#include <QByteArray> #include <QDebug>int main() {testStruct structA;structA.a 1;structA.b 2;struc…

正点原子阿波罗STM32F429IGT6移植zephyr rtos(二)---使用I2C驱动MPU6050

硬件平台&#xff1a;正点原子阿波罗STM32F429IGT6 zephyr版本&#xff1a;Zephyr version 3.7.99 开发环境&#xff1a;ubuntu 24.4 zephyr驱动开发与之前接触到的开发方式可能都不一样&#xff0c;更像是linux驱动开发&#xff0c;zephyr源码里边其实已经有写好的I2C和MPU60…

谷歌SEO:有心栽花花不开,无心插柳柳成荫!

之前一开始是想搞个谷歌SEO免费的技术教程博客&#xff08;https://www.c-sz.com/&#xff09;主要是很多时候遇到在谷歌独立站推广群里的朋友需要咨询和学习一些谷歌技术基础知识&#xff0c;当然我自己也有点小心思&#xff0c;就是希望在谷歌能吸引部分的谷歌SEO爱好者尤其包…

【AI学习】DDPM 无条件去噪扩散概率模型实现(pytorch)

这里主要使用pytorch实现基本的无条件去噪扩散模型&#xff0c;理论上面的推导这里不重点介绍。 原文理论参考&#xff1a; 前向和反向过程示意图 前向过程和后向过程 扩散过程包括正向过程和反向过程。前向过程是基于噪声调度的预定马尔可夫链。噪声表是一组方差 &#xff0…

uniapp小程序原始tabbar添加红点以及信息的方法

如图所示 很多人不知道在uniapp 小程序原始的tabbar上添加红点和红点内的信息有官方的api 从而用自定义的tabbar来做 虽然两种方法都能实现效果&#xff0c;但明显使用自带的更方便 还不如自定义

集合论(ZFC)之 序数(Ordinals) 注解

两个同构&#xff08;isomorphic&#xff09;的良序集&#xff08;Well-Ordered Set&#xff09;&#xff0c;拥有同样的序型&#xff08;Order-Type&#xff09;&#xff0c;那么序数&#xff08;Ordinal&#xff09;就是指良序集的序型&#xff08;Order-Type&#xff09;。 …

React 生命周期 - useEffect 介绍

在 React 中&#xff0c;useEffect 钩子可以被看作是函数组件中的一种副作用管理工具&#xff0c;它的行为可以模拟类组件中的不同生命周期方法。useEffect 的执行时机取决于其依赖项数组&#xff08;第二个参数&#xff09;的设置方式。 根据 useEffect 的使用方式&#xff0c…

在校大学生想从事网络安全工程师,来听听过来人的经验,你会少走很多弯路_学会大学的专业课之后可以去网络安全嘛

大家好&#xff01;一直以来都有一些大学生粉丝私信向我“取经”&#xff0c;看得出很多人对前路多多少少都有些迷茫。 因此&#xff0c;我将大家的问题整理了一下&#xff0c;主要有这几点&#xff1a; 1.国内网安工程师薪资水平&#xff1f; 2.网安行业真实前景&#xff1f;…

怎么提取视频里的音频?非常简单的提取音频方法

怎么提取视频里的音频&#xff1f;在现代数字媒体环境中&#xff0c;视频和音频的结合已成为信息传播和创作的重要手段。随着互联网的发展&#xff0c;视频内容日益丰富&#xff0c;从社交媒体短视频到在线课程&#xff0c;再到电影和纪录片&#xff0c;音频在这些内容中的角色…

全解析:如何评估PLM系统的性价比?

在当今竞争激烈的市场环境中&#xff0c;企业为了提升产品创新能力、优化生产流程、提高市场响应速度&#xff0c;纷纷引入PLM产品生命周期管理系统。然而&#xff0c;面对市场上琳琅满目的PLM系统&#xff0c;如何评估其性价比&#xff0c;成为企业决策的重要课题。本文将从多…