【C】用C语言提取bmp图片像素,并进行K-means聚类分析——容易遇到的问题
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了【C】用C语言提取bmp图片像素,并进行K-means聚类分析——容易遇到的问题,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含7072字,纯文字阅读大概需要11分钟。
内容图文
关于bmp图片的格式,网上有很多文章,具体可以参考百度百科,也有例子程序。这里只提要注意的问题。
(1)结构体定义问题:首先按照百度百科介绍的定义了结构体,但是编译发现重定义BITMAPFILEHEADER等。其实只要包含了Windows.h,里面的wingdi.h就已经定义了处理bmp的结构体,故不需要自己再重复定义。
(2)读取文件的字节对其问题:要使用#pragma pack (1)来方便读取文件头的结构体,否则结构体的大小会由于字节对齐问题改变。不知是否头文件中已经使用了该宏,在我的代码中注释掉#pragma pack (1)也可以正确运行。另外百度到“pack提供数据声明级别的控制,对定义不起作用”,自己也不太清楚这个宏用在哪里比较合适,一般见是在定义结构体的时候,还请各位批评指正。
(3)补齐行数问题:在看百科介绍结构体时,BITMAPINFOHEADER的biSizeImage表示“位图的大小(其中包含了为了补齐行数是4的倍数而添加的空字节),以字节为单位”,并且有相关的计算方法 。我要强调的是提取像素时要排除这些补齐用字节的影响。按照百度百科上提取像素的方法是会将这些补齐用的00字节算入在内的,从而影响后面的算法。
博客园无法上传bmp图片,所以不贴效果图了。有何问题欢迎批评指正
下面是C语言代码供参考:
1 #pragma once 23 #include "targetver.h"45 #include <stdio.h> 6 #include <tchar.h> 7 #include <windows.h> 8 #include "bitmap.h"9 #include <math.h>
bitmap.h:
1 #pragma pack (1)//字节对齐的控制!非常注意! 2/* 3typedef struct tagBITMAPFILEHEADER 4{ 5 WORD bfType;//位图文件的类型,必须为BM(1-2字节) 6 DWORD bfSize;//位图文件的大小,以字节为单位(3-6字节,低位在前) 7 WORD bfReserved1;//位图文件保留字,必须为0(7-8字节) 8 WORD bfReserved2;//位图文件保留字,必须为0(9-10字节) 9 DWORD bfOffBits;//位图数据的起始位置,以相对于位图(11-14字节,低位在前) 10 //文件头的偏移量表示,以字节为单位 11}BITMAPFILEHEADER; 1213typedef struct tagBITMAPINFOHEADER{ 14 DWORD biSize;//本结构所占用字节数(15-18字节) 15 LONG biWidth;//位图的宽度,以像素为单位(19-22字节) 16 LONG biHeight;//位图的高度,以像素为单位(23-26字节) 17 WORD biPlanes;//目标设备的级别,必须为1(27-28字节) 18 WORD biBitCount;//每个像素所需的位数,必须是1(双色),(29-30字节) 19 //4(16色),8(256色)16(高彩色)或24(真彩色)之一 20 DWORD biCompression;//位图压缩类型,必须是0(不压缩),(31-34字节) 21 //1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一 22 DWORD biSizeImage;//位图的大小(其中包含了为了补齐行数是4的倍数而添加的空字节),以字节为单位(35-38字节) 23 LONG biXPelsPerMeter;//位图水平分辨率,每米像素数(39-42字节) 24 LONG biYPelsPerMeter;//位图垂直分辨率,每米像素数(43-46字节) 25 DWORD biClrUsed;//位图实际使用的颜色表中的颜色数(47-50字节) 26 DWORD biClrImportant;//位图显示过程中重要的颜色数(51-54字节) 27}BITMAPINFOHEADER; 2829typedef struct tagRGBQUAD{ 30 BYTE rgbBlue;//蓝色的亮度(值范围为0-255) 31 BYTE rgbGreen;//绿色的亮度(值范围为0-255) 32 BYTE rgbRed;//红色的亮度(值范围为0-255) 33 BYTE rgbReserved;//保留,必须为0 34}RGBQUAD; 35*/36 typedef struct37{ 38 BYTE b; 39 BYTE g; 40 BYTE r; 41}RGB; 4243//带有坐标的颜色RGB表示44 typedef struct45{ 46 RGB rgb; 47int height; 48int width; 49} RGB_EX; 50#pragma pack ()//字节对齐的控制
main.c:
1 // 针对图片实现K-means聚类算法.cpp : 定义控制台应用程序的入口点。 2 #include "stdafx.h" 3 4float distance(RGB x, RGB mean); 5int kmeans_img(RGB **Img, LONG ImgWidth, LONG ImgHeight, ULONG lCount, USHORT K); 6 7int _tmain(int argc, _TCHAR* argv[]) 8{ 9//#pragma pack (1)//字节对齐的控制!非常注意! 10 BITMAPFILEHEADER fileHeader; 11 BITMAPINFOHEADER infoHeader; 12 FILE* pfin; fopen_s(&pfin, "test2.bmp","rb"); 13 FILE* pfout; fopen_s(&pfout, "ouput.bmp","wb"); 14//ReadtheBitmapfileheader; 15 fread(&fileHeader, sizeof(BITMAPFILEHEADER), 1, pfin); 16//ReadtheBitmapinfoheader; 17 fread(&infoHeader, sizeof(BITMAPINFOHEADER), 1, pfin); 18//为简化代码,只处理24位彩色 19if(infoHeader.biBitCount==24) { 20int size = infoHeader.biWidth * infoHeader.biHeight; 21 RGB **ppImg = NULL; 22int r; 23//开辟空间并读入图片 24//RGB img[infoHeader.biHeight][infoHeader.biWidth]; //这里有错误,尺度改为常亮 25//fread(ppImg, sizeof(RGB), size, pfin); 26 ppImg = (RGB**)malloc(infoHeader.biHeight * sizeof(RGB*)); 27if (!ppImg) 28return -1; 29//注意!需要处理补齐字节问题:每行字节数目必须是4的整数倍 30 r = infoHeader.biWidth % 4; 31for (int i = 0; i < infoHeader.biHeight; i++) { 32 ppImg[i] = (RGB*)malloc(sizeof(RGB) * infoHeader.biWidth); 33if (ppImg[i]) { 34 fread(ppImg[i], sizeof(RGB), infoHeader.biWidth, pfin); 35 fseek(pfin, r, SEEK_CUR); 36 } 37else 38return -1; 39 } 40 41/* 42 //把第50行染成黑色 43 int i=0; 44 for(;i<infoHeader.biWidth;i++) { 45 ppImg[50][i].b = ppImg[50][i].g = ppImg[50][i].r = 0; 46 } 47*/ 48 49 kmeans_img(ppImg, infoHeader.biWidth, infoHeader.biHeight, 2000, 5); 50 51//将修改后的图片保存到文件 52 fileHeader.bfSize = infoHeader.biHeight * infoHeader.biWidth * 3 + fileHeader.bfOffBits; 53 fwrite(&fileHeader,sizeof(fileHeader),1,pfout); 54 fwrite(&infoHeader,sizeof(infoHeader),1,pfout); 55for (int i = 0; i < infoHeader.biHeight; i++) { 56 fwrite(ppImg[i],sizeof(RGB),infoHeader.biWidth,pfout); 57int temp = r; 58while (temp--) 59 { 60 fputc(0, pfout); 61 } 62 } 63 64//释放图片占用内存 65for (int i = 0; i < infoHeader.biHeight; i++) 66free(ppImg[i]); 67free(ppImg); 68 } 69 fclose(pfin); 70 fclose(pfout); 71//#pragma pack () 72return0; 73} 74 75/* 76对图片像素使用K-means算法聚类,聚成K类 77Img:RGB矩阵形式的图片。第一维是高度Height。Img[ImgHeight][ImgWidth]。 78为保证算法正确性,图片中应已经剔除了补齐字节用的00 79ImgWidth:图片宽 80ImgHeight:图片高 81lCount:迭代次数 82K:聚类数目 83 84*/ 85int kmeans_img(RGB **Img, LONG ImgWidth, LONG ImgHeight, ULONG lCount, USHORT K) 86{ 87int iFlag;//收敛后置为0 88 RGB *means = (RGB*)malloc(K * sizeof(RGB));//K个中心 89 RGB_EX **Cluster = NULL;//存放簇 90int *ClusterLength = NULL; 91 Cluster = (RGB_EX**)malloc(K * sizeof(RGB_EX*)); 92 ClusterLength = (int *)malloc(K * sizeof(int)); 93for (int i = 0; i < K; i++) { 94//随意指定K个中心,应该还有更好的算法. 95 means[i] = Img[(ImgHeight/(i+1))-1][(ImgWidth/(i+1))-1]; 96//开辟簇的存储空间 97 Cluster[i] = (RGB_EX*)malloc(ImgHeight * ImgWidth * sizeof(RGB_EX)); 98 } 99100 iFlag = K; 101//开始迭代102while (lCount-- && iFlag) 103 { 104 iFlag = K; 105//每次聚类前要初始化106for (int i = 0; i < K; i++) 107 ClusterLength[i] = 0; 108109//对每个像素循环,归置到相应的簇里110for (int i = 0; i < ImgHeight; i++) { 111for (int j = 0; j < ImgWidth; j++) { 112int iClusterIndex = 0; 113float fMinDistance = 255 * 255 + 255 *255 + 255 * 255; 114float d = 0; 115for (int k = 0; k < K; k++) { 116 d = distance(Img[i][j], means[k]); 117 fMinDistance = fMinDistance > d ? iClusterIndex = k, d : fMinDistance; 118 } 119 Cluster[iClusterIndex][ClusterLength[iClusterIndex]].rgb = Img[i][j]; 120 Cluster[iClusterIndex][ClusterLength[iClusterIndex]].height = i; 121 Cluster[iClusterIndex][ClusterLength[iClusterIndex]++].width = j; 122 } 123 } 124125//重新计算每个簇的均值126for (int i = 0; i < K; i++) { 127 unsigned long sumR = 0, sumG = 0, sumB = 0; 128 BYTE R = 0, G = 0, B = 0; 129for (int j = 0; j < ClusterLength[i]; j++) { 130 sumR += Cluster[i][j].rgb.r; 131 sumG += Cluster[i][j].rgb.g; 132 sumB += Cluster[i][j].rgb.b; 133 } 134if (ClusterLength[i]) { 135 R = sumR / ClusterLength[i]; 136 G = sumG / ClusterLength[i]; 137 B = sumB / ClusterLength[i]; 138 } 139if ( means[i].r == R && means[i].g == G && means[i].b == B) 140 iFlag --;//若均值不变则终止循环141else { 142 means[i].r = R; 143 means[i].g = G; 144 means[i].b = B; 145 } 146 } 147 } 148149//迭代结束后为每簇上色表达聚类结果150for (int i = 0; i < K; i++) { 151for (int j = 0; j < ClusterLength[i]; j++) { 152 Img[Cluster[i][j].height][Cluster[i][j].width].r = means[i].r; 153 Img[Cluster[i][j].height][Cluster[i][j].width].b = means[i].b; 154 Img[Cluster[i][j].height][Cluster[i][j].width].g = means[i].g; 155156 } 157 } 158159//释放内存160for (int i = 0; i < K; i++) { 161free(Cluster[i]); 162 } 163free(Cluster); 164free (means); 165free(ClusterLength); 166167return0; 168} 169170float distance(RGB x, RGB mean) 171{ 172return sqrt( pow((float)(x.b - mean.b),2) + 173 pow((float)(x.g - mean.g),2) + 174 pow((float)(x.r - mean.r),2) 175 ); 176 }
By ascii0x03, 2015.10.19
原文:http://www.cnblogs.com/ascii0x03/p/4892647.html
内容总结
以上是互联网集市为您收集整理的【C】用C语言提取bmp图片像素,并进行K-means聚类分析——容易遇到的问题全部内容,希望文章能够帮你解决【C】用C语言提取bmp图片像素,并进行K-means聚类分析——容易遇到的问题所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。