由於工作需要,時常需要將像素矩陣保存圖片顯示觀看。為此,特地總結了三種使用純C++代碼生成bmp圖片的方法。分別是使用自定義數據、從外界導入的txt和csv以及從圖片中導入的數據。
-
1.使用自定義數據保存為bmp圖片
自定義數據可以是使用公式生成,或者是根據自己需求自己定義的數據,范圍為0-255,分別對應從黑色到白色。代碼生成過程如下:
View Code1 #pragma warning(disable:4996) 2 #include<iostream> 3 #include<string> 4 using namespace std; 5 6 //#define FrameSize 960*960 //視頻幀大小 7 int width = 120, height = 120; 8 #define FrameNum 300 //yuv幀數 9 static const double S_PI = 3.14159265358979323846; 10 #define scos(x) cos((double)(x)) 11 #define stan(x) tan((double)(x)) 12 #define ssqrt(x) sqrt((double)(x)) 13 #define ET_SIZE 300 14 char errorText[ET_SIZE]; 15 16 void errorMsg(const char *msg) 17 { 18 printf("error:%s\n", msg); 19 #ifdef _WIN32 20 system("pause"); 21 #endif 22 exit(-1); 23 } 24 25 void readSequence(unsigned char *frames) 26 { 27 //Test start 28 for (int y = 0; y < height; y++) 29 { 30 for (int x = 0; x < width; x++) 31 { 32 //使用公式生成像素數據 33 float pu0 = (float)((2.0*(x + 0.5)) / width - 1.0); 34 float pv0 = (float)((2.0*(y + 0.5)) / height - 1.0); 35 36 double tu0 = stan(pu0*S_PI / 4.0); 37 double tv0 = stan(pv0*S_PI / 4.0); 38 double value= 1.0 / (scos(pu0*S_PI / 4.0)*scos(pu0*S_PI / 4.0)*scos(pv0*S_PI / 4.0)*scos(pv0*S_PI / 4.0) * (tu0*tu0 + tv0*tv0 + 1.0) * ssqrt(tu0*tu0 + tv0*tv0 + 1.0)); 39 40 //將值從(0,1)放大到(0,255) 41 value= 255.0*value; 42 //將值從(128,255)放大到(0,255),增加圖像對比度 43 frames[y*width + x] = 2.0*value- 255.0; 44 } 45 } 46 } 47 48 void write_bmpheader(unsigned char *bitmap, int offset, int bytes, int value) 49 { 50 int i; 51 for (i = 0; i < bytes; i++) 52 bitmap[offset + i] = (value >> (i << 3)) & 0xFF; 53 } 54 55 unsigned char *convertToBmp(unsigned char *inputImg, int width, int height, int *ouputSize) 56 { 57 /*create a bmp format file*/ 58 int bitmap_x = (int)ceil((double)width * 3 / 4) * 4; 59 unsigned char *bitmap = (unsigned char*)malloc(sizeof(unsigned char)*height*bitmap_x + 54); 60 61 bitmap[0] = 'B'; 62 bitmap[1] = 'M'; 63 write_bmpheader(bitmap, 2, 4, height*bitmap_x + 54); //whole file size 64 write_bmpheader(bitmap, 0xA, 4, 54); //offset before bitmap raw data 65 write_bmpheader(bitmap, 0xE, 4, 40); //length of bitmap info header 66 write_bmpheader(bitmap, 0x12, 4, width); //width 67 write_bmpheader(bitmap, 0x16, 4, height); //height 68 write_bmpheader(bitmap, 0x1A, 2, 1); 69 write_bmpheader(bitmap, 0x1C, 2, 24); //bit per pixel 70 write_bmpheader(bitmap, 0x1E, 4, 0); //compression 71 write_bmpheader(bitmap, 0x22, 4, height*bitmap_x); //size of bitmap raw data 72 73 for (int i = 0x26; i < 0x36; i++) 74 bitmap[i] = 0; 75 int k = 54; 76 for (int i = height - 1; i >= 0; i--) { 77 int j; 78 for (j = 0; j < width; j++) { 79 int index = i*width + j; 80 for (int l = 0; l < 3; l++) 81 bitmap[k++] = inputImg[index]; 82 } 83 j *= 3; 84 while (j < bitmap_x) { 85 bitmap[k++] = 0; 86 j++; 87 } 88 } 89 *ouputSize = k; 90 return bitmap; 91 } 92 93 void saveToBmp(unsigned char *inputImg, int width, int height, char *outputFileName) 94 { 95 int size; 96 unsigned char *bmp = convertToBmp(inputImg, width, height, &size); 97 FILE *fp = fopen(outputFileName, "wb+"); 98 if (fp == NULL) { 99 sprintf(errorText, "Could not open file: %s", outputFileName); 100 errorMsg(errorText); 101 } 102 fwrite(bmp, 1, size, fp); 103 fclose(fp); 104 free(bmp); 105 } 106 int main() 107 { 108 unsigned char *oriFrames; 109 oriFrames = (unsigned char*)malloc(sizeof(unsigned char) * width * height); 110 readSequence(oriFrames); 111 112 char imgName[30]; 113 sprintf(imgName, "F:\\pictures\\Bitmap_Weight_Map_Convex2.bmp"); 114 //矩陣oriFrames[i]可以是任何你想保存為圖片的像素矩陣,這里是yuv視頻圖像每一幀的像素數據 115 saveToBmp(oriFrames, width, height, imgName); 116 //system("pause"); 117 }
-
2.從外界導入的txt和csv保存為bmp圖片
將數據導入txt中:
View Code1 #pragma warning(disable:4996) 2 #include <stdio.h> 3 #include <stdlib.h> 4 int main() 5 { 6 //文件寫操作txt 7 FILE *fp;//文件指針 8 int i, d; 9 /*文件的打開*/ 10 fp = fopen("E:\\VS_Test_Code\\data.txt", "w");//fopen打開文件,這個文件可以是當前不存在的。“w”以寫入的形式打開,“r”以讀的形式打開 11 if (fp == NULL) //判斷如果文件指針為空 12 { 13 printf("File cannot open! "); 14 exit(0);//在以0的形式退出,必須在文件開頭有#include <stdlib.h>,stdlib 頭文件即standard library標准庫頭文件 15 } 16 //寫入數據 17 for (i = 0; i < 10; i++) 18 { 19 scanf("%d", &d);//用戶輸入 20 fprintf(fp, "%d,", d);//寫入指針fp,寫入的東西就是剛才的用戶輸入的d,注意這里的fp和d沒有引號 21 } 22 //關閉文件 23 fclose(fp); 24 }
從txt中讀取數據:
View Code1 #pragma warning(disable:4996) 2 #include <stdio.h> 3 #include <stdlib.h> 4 int main() 5 { 6 //文件讀操作txt 7 FILE *fp;//文件指針 8 int i, d; 9 /*文件的打開*/ 10 fp = fopen("E:\\VS_Test_Code\\data.txt", "r");//fopen打開文件,這個文件可以是當前不存在的。“w”以寫入的形式打開,“r”以讀的形式打開 11 if (fp == NULL) //判斷如果文件指針為空 12 { 13 printf("File cannot open! "); 14 exit(0);//在以0的形式退出,必須在文件開頭有#include <stdlib.h>,stdlib 頭文件即standard library標准庫頭文件 15 } 16 int *array = (int*)malloc(sizeof(int) * 10); 17 //讀取數據 18 for (i = 0; i < 10; i++) 19 { 20 fscanf(fp, "%d,", &array[i]);//從文件輸入 21 printf("%d ", array[i]);//寫入指針fp,寫入的東西就是剛才的用戶輸入的d,注意這里的fp和d沒有引號 22 } 23 printf("\n"); 24 //關閉文件 25 fclose(fp); 26 system("pause");//使窗口保持不關閉 27 }
將數據導入csv中:
View Code1 #pragma warning(disable:4996) 2 #include <stdio.h> 3 #include <stdlib.h> 4 int main() 5 { 6 //文件寫操作csv 7 FILE *fp;//文件指針 8 int i, No; 9 double salary; 10 fp = fopen("E:\\VS_Test_Code\\data.csv", "w");//fopen打開文件,這個文件可以是當前不存在的。“w”以寫入的形式打開,“r”以讀的形式打開 11 if (fp == NULL) //判斷如果文件指針為空 12 { 13 printf("File cannot open! "); 14 exit(0);//在以0的形式退出,必須在文件開頭有#include <stdlib.h>,stdlib 頭文件即standard library標准庫頭文件 15 } 16 //寫入數據 17 for (i = 0; i < 5; i++) 18 { 19 scanf("%d %lf", &No, &salary);//用戶輸入,double一定要用%lf 20 fprintf(fp, "%d %.2f\n", No, salary);//寫入指針fp,寫入的東西就是剛才的用戶輸入的d,注意這里的fp和d沒有引號 21 } 22 //關閉文件 23 fclose(fp); 24 }
從csv中讀取數據:
View Code1 #pragma warning(disable:4996) 2 #include <stdio.h> 3 #include <stdlib.h> 4 int main() 5 { 6 //文件讀操作csv 7 FILE *fp;//文件指針 8 int i, No; 9 double salary; 10 fp = fopen("E:\\VS_Test_Code\\data.csv", "r");//fopen打開文件,這個文件可以是當前不存在的。“w”以寫入的形式打開,“r”以讀的形式打開 11 if (fp == NULL) //判斷如果文件指針為空 12 { 13 printf("File cannot open! "); 14 exit(0);//在以0的形式退出,必須在文件開頭有#include <stdlib.h>,stdlib 頭文件即standard library標准庫頭文件 15 } 16 //讀取數據 17 for (i = 0; i < 5; i++) 18 { 19 fscanf(fp, "%d %lf", &No, &salary);//用戶輸入,double要用%lf 20 printf("%d\t%.2f\n", No, salary);//寫入指針fp,寫入的東西就是剛才的用戶輸入的d,注意這里的fp和d沒有引號 21 } 22 //關閉文件 23 fclose(fp); 24 system("pause"); 25 }
將txt中的數據保存為bmp圖片
View Code1 #pragma warning(disable:4996) 2 #include<iostream> 3 #include<string> 4 using namespace std; 5 6 #define FrameSize 100*100 //視頻幀大小 7 #define FrameNum 10 //yuv幀數 8 #define ET_SIZE 300 9 char errorText[ET_SIZE]; 10 11 void errorMsg(const char *msg) { 12 13 printf("error:%s\n", msg); 14 15 #ifdef _WIN32 16 17 system("pause"); 18 19 #endif 20 21 exit(-1); 22 23 } 24 25 void readSequence(char *fileName, unsigned char **frames) 26 { 27 FILE *fp = fopen(fileName, "rb"); 28 if (fp == NULL) 29 { 30 sprintf(errorText, "File %s doesn't exist\n", fileName); 31 errorMsg(errorText); 32 } 33 34 int uvSize = FrameSize / 2; //H.264編解碼獲得的關鍵幀都是彩色序列,這里主要是提取亮度分量Y。 35 unsigned char *buf = (unsigned char *)malloc(sizeof(unsigned char) * uvSize); 36 for (int i = 0; i < FrameNum; i++) { 37 //read y 38 if (fread(frames[i], 1, FrameSize, fp) != FrameSize) { //每一個keyFrames[i]分配的是 (unsigned char) * FrameSize的大小,所以fread要讀的每個數據項的字節數為1,可以表示每個像素點亮度范圍0~255 39 sprintf(errorText, "Input sequence %s is not enough", fileName); 40 errorMsg(errorText); 41 } 42 43 //read u,v 44 fread(buf, 1, uvSize, fp); 45 } 46 free(buf); 47 fclose(fp); 48 } 49 50 void write_bmpheader(unsigned char *bitmap, int offset, int bytes, int value) { 51 int i; 52 for (i = 0; i < bytes; i++) 53 bitmap[offset + i] = (value >> (i << 3)) & 0xFF; 54 } 55 56 unsigned char *convertToBmp(unsigned char *inputImg, int width, int height, int *ouputSize) { 57 58 /*create a bmp format file*/ 59 int bitmap_x = (int)ceil((double)width * 3 / 4) * 4; 60 unsigned char *bitmap = (unsigned char*)malloc(sizeof(unsigned char)*height*bitmap_x + 54); 61 62 bitmap[0] = 'B'; 63 bitmap[1] = 'M'; 64 write_bmpheader(bitmap, 2, 4, height*bitmap_x + 54); //whole file size 65 write_bmpheader(bitmap, 0xA, 4, 54); //offset before bitmap raw data 66 write_bmpheader(bitmap, 0xE, 4, 40); //length of bitmap info header 67 write_bmpheader(bitmap, 0x12, 4, width); //width 68 write_bmpheader(bitmap, 0x16, 4, height); //height 69 write_bmpheader(bitmap, 0x1A, 2, 1); 70 write_bmpheader(bitmap, 0x1C, 2, 24); //bit per pixel 71 write_bmpheader(bitmap, 0x1E, 4, 0); //compression 72 write_bmpheader(bitmap, 0x22, 4, height*bitmap_x); //size of bitmap raw data 73 74 for (int i = 0x26; i < 0x36; i++) 75 bitmap[i] = 0; 76 77 int k = 54; 78 for (int i = height - 1; i >= 0; i--) { 79 int j; 80 for (j = 0; j < width; j++) { 81 int index = i*width + j; 82 for (int l = 0; l < 3; l++) 83 bitmap[k++] = inputImg[index]; 84 } 85 j *= 3; 86 while (j < bitmap_x) { 87 bitmap[k++] = 0; 88 j++; 89 } 90 } 91 92 *ouputSize = k; 93 return bitmap; 94 } 95 96 void saveToBmp(unsigned char *inputImg, int width, int height, char *outputFileName) { 97 int size; 98 unsigned char *bmp = convertToBmp(inputImg, width, height, &size); 99 FILE *fp = fopen(outputFileName, "wb+"); 100 if (fp == NULL) { 101 sprintf(errorText, "Could not open file: %s", outputFileName); 102 errorMsg(errorText); 103 104 } 105 fwrite(bmp, 1, size, fp); 106 fclose(fp); 107 free(bmp); 108 } 109 110 int main() { 111 int width = 120, height = 120; 112 113 unsigned char **oriFrames; 114 oriFrames = (unsigned char**)malloc(sizeof(unsigned char*) * FrameNum); 115 for (int i = 0; i < FrameNum; i++) { 116 oriFrames[i] = (unsigned char*)malloc(sizeof(unsigned char) * FrameSize); 117 } 118 119 ////Test寫入 120 //readSequence("E:\\Research\\YUV_Sequences\\2D\\BasketballPass_416x240_50\\BasketballPass_416x240_50.yuv", oriFrames); 121 //FILE *fp; 122 //fp = fopen("E:\\VS_Test_Code\\cnblogData.txt", "w"); 123 //if (fp == NULL) 124 //{ 125 // exit(0); 126 //} 127 //for (int i = 0; i < FrameNum; i++) 128 //{ 129 // for (int j = 0; j < FrameSize; j++) 130 // { 131 // fprintf(fp, "%d,", oriFrames[i][j]); 132 // } 133 // fprintf(fp, "\n"); 134 //} 135 ////Test寫入 136 137 //Test讀取 138 FILE *fp; 139 fp = fopen("E:\\VS_Test_Code\\cnblogData.txt", "r"); 140 if (fp == NULL) 141 { 142 exit(0); 143 } 144 for (int i = 0; i < FrameNum; i++) 145 { 146 for (int j = 0; j < FrameSize; j++) 147 { 148 fscanf(fp, "%d,", &oriFrames[i][j]);//必須和fprintf格式保持一致 149 } 150 } 151 for (int i = 0; i < FrameNum; i++) 152 { 153 for (int j = 0; j < FrameSize; j++) 154 { 155 printf("%d ", oriFrames[i][j]); 156 } 157 printf("\n"); 158 } 159 //Test讀取 160 161 char imgName[30]; 162 for (int i = 0; i < FrameNum; i++) { 163 sprintf(imgName, "F:\\pictures\\ReconsFrame%d.bmp", i); 164 //矩陣oriFrames[i]可以是任何你想保存為圖片的像素矩陣,這里是yuv視頻圖像每一幀的像素數據 165 saveToBmp(oriFrames[i], width, height, imgName); 166 } 167 system("pause"); 168 }
-
3.從圖片中導入的數據保存為bmp圖片
從圖片中導入圖像數據,將其存儲為像素矩陣,像素值的范圍是0-255,分別對應從黑色到白色,並將像素矩陣保存為bmp圖片。代碼如下所示:
View Code1 #pragma warning(disable:4996) 2 #include<iostream> 3 #include<string> 4 using namespace std; 5 6 #define FrameSize 416*240 //視頻幀大小 7 #define FrameNum 300 //yuv幀數 8 #define ET_SIZE 300 9 char errorText[ET_SIZE]; 10 11 void errorMsg(const char *msg) 12 { 13 printf("error:%s\n", msg); 14 #ifdef _WIN32 15 system("pause"); 16 #endif 17 exit(-1); 18 19 } 20 21 void readSequence(char *fileName, unsigned char **frames) 22 { 23 FILE *fp = fopen(fileName, "rb"); 24 if (fp == NULL) 25 { 26 sprintf(errorText, "File %s doesn't exist\n", fileName); 27 errorMsg(errorText); 28 } 29 int uvSize = FrameSize / 2; //H.264編解碼獲得的關鍵幀都是彩色序列,這里主要是提取亮度分量Y。 30 unsigned char *buf = (unsigned char *)malloc(sizeof(unsigned char) * uvSize); 31 for (int i = 0; i < FrameNum; i++) { 32 //read y 33 if (fread(frames[i], 1, FrameSize, fp) != FrameSize) { //每一個keyFrames[i]分配的是 (unsigned char) * FrameSize的大小,所以fread要讀的每個數據項的字節數為1,可以表示每個像素點亮度范圍0~255 34 sprintf(errorText, "Input sequence %s is not enough", fileName); 35 errorMsg(errorText); 36 } 37 //read u,v 38 fread(buf, 1, uvSize, fp); 39 } 40 free(buf); 41 fclose(fp); 42 } 43 44 45 46 void write_bmpheader(unsigned char *bitmap, int offset, int bytes, int value) 47 { 48 int i; 49 for (i = 0; i < bytes; i++) 50 bitmap[offset + i] = (value >> (i << 3)) & 0xFF; 51 } 52 53 unsigned char *convertToBmp(unsigned char *inputImg, int width, int height, int *ouputSize) 54 { 55 /*create a bmp format file*/ 56 int bitmap_x = (int)ceil((double)width * 3 / 4) * 4; 57 unsigned char *bitmap = (unsigned char*)malloc(sizeof(unsigned char)*height*bitmap_x + 54); 58 59 bitmap[0] = 'B'; 60 bitmap[1] = 'M'; 61 write_bmpheader(bitmap, 2, 4, height*bitmap_x + 54); //whole file size 62 write_bmpheader(bitmap, 0xA, 4, 54); //offset before bitmap raw data 63 write_bmpheader(bitmap, 0xE, 4, 40); //length of bitmap info header 64 write_bmpheader(bitmap, 0x12, 4, width); //width 65 write_bmpheader(bitmap, 0x16, 4, height); //height 66 write_bmpheader(bitmap, 0x1A, 2, 1); 67 write_bmpheader(bitmap, 0x1C, 2, 24); //bit per pixel 68 write_bmpheader(bitmap, 0x1E, 4, 0); //compression 69 write_bmpheader(bitmap, 0x22, 4, height*bitmap_x); //size of bitmap raw data 70 71 for (int i = 0x26; i < 0x36; i++) 72 bitmap[i] = 0; 73 74 int k = 54; 75 for (int i = height - 1; i >= 0; i--) { 76 int j; 77 for (j = 0; j < width; j++) { 78 int index = i*width + j; 79 for (int l = 0; l < 3; l++) 80 bitmap[k++] = inputImg[index]; 81 } 82 j *= 3; 83 while (j < bitmap_x) { 84 bitmap[k++] = 0; 85 j++; 86 } 87 } 88 89 *ouputSize = k; 90 return bitmap; 91 } 92 93 void saveToBmp(unsigned char *inputImg, int width, int height, char *outputFileName) 94 { 95 int size; 96 unsigned char *bmp = convertToBmp(inputImg, width, height, &size); 97 FILE *fp = fopen(outputFileName, "wb+"); 98 if (fp == NULL) { 99 sprintf(errorText, "Could not open file: %s", outputFileName); 100 errorMsg(errorText); 101 102 } 103 fwrite(bmp, 1, size, fp); 104 fclose(fp); 105 free(bmp); 106 } 107 108 int main() 109 { 110 int width = 416, height = 240; 111 112 unsigned char **oriFrames; 113 oriFrames = (unsigned char**)malloc(sizeof(unsigned char*) * FrameNum); 114 for (int i = 0; i < FrameNum; i++) { 115 oriFrames[i] = (unsigned char*)malloc(sizeof(unsigned char) * FrameSize); 116 } 117 118 //獲取圖像的數據 119 readSequence("E:\\Research\\YUV_Sequences\\2D\\BasketballPass_416x240_50\\BasketballPass_416x240_50.yuv", oriFrames); 120 121 char imgName[30]; 122 for (int i = 0; i < 10 /*FrameNum*/; i++) { 123 sprintf(imgName, "F:\\pictures\\ReconsFrame%d.bmp", i); 124 //矩陣oriFrames[i]可以是任何你想保存為圖片的像素矩陣,這里是yuv視頻圖像每一幀的像素數據 125 saveToBmp(oriFrames[i], width, height, imgName); 126 } 127 }
-
4.參考文獻
https://blog.csdn.net/sinat_33718563/article/details/79424981
https://blog.csdn.net/zzwtyds/article/details/75095698
