使用 Opengl 和 c++ 读取 PPM 文件并显示。颜色不正确
Read PPM file and display with Opengl and c++. The colors are incorrect
我正在开发一个读取 PPM 文件(P6 格式)并使用 Opengl 和 C++ 显示它的程序。
PPM 图像可以用我的代码显示,但图像的颜色不正确。这个人的脸应该是棕色的,背景应该是蓝色的。
我用 ifstream 读取文件并将数据放入 char 数组 dataByte[] 中。然后我使用 glDrawPixels() 来显示图像。它适用于 PGM 文件。
这是我的代码。我需要对 image.The 操作进行一些操作,但只有当我显示 PPM 文件时,图像的颜色才不像它在 photoshop 中显示的那样。
背景应该是蓝色的,但它变成了红色等等...我现在无法上传图片所以这里是图片的屏幕截图link
the image should be display
but it display in this way
我认为问题出在我读取数据的函数上。
#include "stdafx.h"
#include <stdlib.h>
#include <GL/glut.h>
#include <iostream>
#include <fstream>
#include <string>
#include <stdio.h>
using namespace std;
GLint width;
GLint height;
GLint wholeLength;
GLint grayLevel;
//GLubyte *dataByte;
char* dataByte;
GLint type;
//ignore the comment in PPM
void ignoreComment(ifstream &f){
char buf[1024];
char t;
t=f.peek();
while (t=='\n' || t=='\r'){
f.get();
t=f.peek();
}
if(t=='#'){
f.getline(buf,1023);
}
}
这是我读取图像并将数据放入dataByte[]中的函数。我认为问题是因为我从 PPM 文件中获取数据的方式。但是不知道怎么解决
void readImage(string fname){
ifstream f;
f.open(fname.c_str(), ifstream::in | ifstream::binary);
cout<<fname.c_str()<<endl;
if(!f.is_open() ){
cout<<"Cannot open the file"<<endl;
return;
}
else
cout<<"opened"<<endl;
//get type
ignoreComment(f);
string temp;
f >> temp;
if( (!(temp[0]=='P' ) && !(temp[0]=='p' ) )||
( !(temp[1]=='6' ) && !(temp[1]=='5' ))
){
cout<<temp<<endl;
cout<<"cannot read this format"<<endl;
f.close();
return;
}
else{
cout<<"file opened"<<endl;
cout<<temp<<endl;
}
if(temp[1]=='5'){
type=5;
cout<<"type:"<<type<<endl;
}
if(temp[1]=='6'){
type=6;
cout<<"type:"<<type<<endl;
}
//get width,height
ignoreComment(f);
f >> width;
ignoreComment(f);
f >> height;
ignoreComment(f);
f >> grayLevel;
if(width < 1 || height < 1 || grayLevel < 0 || grayLevel >255){
cout<<"Cannot get the size or gray level"<<endl;
f.close();
return;
}
//allocate data size
if( type==5){
wholeLength=width*height;
cout<<"width="<<width<<" height:"<<height<<endl;
}
if(type==6){
wholeLength=3*width*height;
cout<<"width="<<width<<" height:"<<height<<endl;
}
if(type==5 || type ==6){
//dataByte=new GLubyte[wholeLength];
dataByte=new unsigned char[wholeLength];
//f.read((char*)&dataByte[0], wholeLength);
//GLubyte j;
int w;
if(type==5)
w=width;
if(type==6)
w=3*width;
int count=0;int counth=0;
for(int i=height;i>0;i--){
for(int k=0;k<w;k++){
//j=(GLubyte)f.get();
//dataByte[(i-1)*w+k]=j;
f.read((char*)&dataByte[(i-1)*w+k],sizeof(unsigned char));
count++;
}
cout<<"count:"<<count<<endl;
count=0;
counth++;
}
cout<<"counth:"<<counth<<endl;
}
f.close();
}
int main(int argc, char *argv[] ) {
//string n;
//cout<<"Please enter the name of the image"<<endl;
//cin>>n;
readImage("small.ppm");
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB);
ori();
getChoice();
glutMainLoop();
return 0;
}
这是我的显示功能。他们可以显示PGM文件和PPM文件。
void drawAsType(char * d){
if(type==5){
glDrawPixels(width,height,GL_LUMINANCE,GL_UNSIGNED_BYTE,d);
glFlush();
glutSwapBuffers();
}
if(type==6 ){
glDrawPixels(width,height,GL_RGB,GL_UNSIGNED_BYTE,d);
glFlush();
glutSwapBuffers();
}
}
void changeSize(int w,int h){
glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0,(GLfloat)w,0.0,(GLfloat)h);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void display(void){
glClear(GL_COLOR_BUFFER_BIT);
glRasterPos2i(0,0);
glColor3f(1.0f,1.0f,1.0f);
drawAsType(dataByte);
}
void ori(){
glutInitWindowSize(width,height);
glutCreateWindow("Origin");
glutReshapeFunc(changeSize);
glutDisplayFunc(&display);
}
谁能帮我解决这个问题?
感谢 haraldK 的。
我发现原因是因为在 ignoreComent() 函数中我使用 peek() 来检查下一个字符是 '\n' 还是 '\t' 或 '#'。
void ignoreComment(ifstream &f){
char buf[1024];
char t;
while ( t=f.peek(),t=='\n'|| t=='\r'){
f.get();
}
if(t=='#'){
f.getline(buf,1023);
}
}
peek() 函数 returns 输入序列中的下一个字符,不提取它:该字符作为下一个要从流中提取的字符 .--表格 cplusplus.com
所以在最后一次调用peek() 之后检查garyLevel 的行。
ignoreComment(f);
由于garyLevel的第一个字符是'2',因为'2'不应该被忽略,所以程序执行下一行f >> grayLevel
然后执行读取图像数据部分。 But 流中的第一个字符是来自 peek() 的“2”。 所以我的数组 dataByte[]
的第一个字符将是 2 而不是真正的第一个字符图像块。
解决方法是替换'2'。所以我应该使用 f.get()
在我开始读取 RGB 数据之前再次。
所以只需在两个for循环之前添加f.get()
if(type==5 || type ==6){
dataByte=new char[wholeLength];
f.get(); /*ADD THIS GUY!*/
int w;
if(type==5)
w=width;
if(type==6)
w=3*width;
int count=0;int counth=0;
char t;
for(int i=height;i>0;i--){
for(int k=0;k<w;k++){
//read image RGB data
}
}
我正在开发一个读取 PPM 文件(P6 格式)并使用 Opengl 和 C++ 显示它的程序。
PPM 图像可以用我的代码显示,但图像的颜色不正确。这个人的脸应该是棕色的,背景应该是蓝色的。
我用 ifstream 读取文件并将数据放入 char 数组 dataByte[] 中。然后我使用 glDrawPixels() 来显示图像。它适用于 PGM 文件。
这是我的代码。我需要对 image.The 操作进行一些操作,但只有当我显示 PPM 文件时,图像的颜色才不像它在 photoshop 中显示的那样。
背景应该是蓝色的,但它变成了红色等等...我现在无法上传图片所以这里是图片的屏幕截图link
the image should be display but it display in this way
我认为问题出在我读取数据的函数上。
#include "stdafx.h"
#include <stdlib.h>
#include <GL/glut.h>
#include <iostream>
#include <fstream>
#include <string>
#include <stdio.h>
using namespace std;
GLint width;
GLint height;
GLint wholeLength;
GLint grayLevel;
//GLubyte *dataByte;
char* dataByte;
GLint type;
//ignore the comment in PPM
void ignoreComment(ifstream &f){
char buf[1024];
char t;
t=f.peek();
while (t=='\n' || t=='\r'){
f.get();
t=f.peek();
}
if(t=='#'){
f.getline(buf,1023);
}
}
这是我读取图像并将数据放入dataByte[]中的函数。我认为问题是因为我从 PPM 文件中获取数据的方式。但是不知道怎么解决
void readImage(string fname){
ifstream f;
f.open(fname.c_str(), ifstream::in | ifstream::binary);
cout<<fname.c_str()<<endl;
if(!f.is_open() ){
cout<<"Cannot open the file"<<endl;
return;
}
else
cout<<"opened"<<endl;
//get type
ignoreComment(f);
string temp;
f >> temp;
if( (!(temp[0]=='P' ) && !(temp[0]=='p' ) )||
( !(temp[1]=='6' ) && !(temp[1]=='5' ))
){
cout<<temp<<endl;
cout<<"cannot read this format"<<endl;
f.close();
return;
}
else{
cout<<"file opened"<<endl;
cout<<temp<<endl;
}
if(temp[1]=='5'){
type=5;
cout<<"type:"<<type<<endl;
}
if(temp[1]=='6'){
type=6;
cout<<"type:"<<type<<endl;
}
//get width,height
ignoreComment(f);
f >> width;
ignoreComment(f);
f >> height;
ignoreComment(f);
f >> grayLevel;
if(width < 1 || height < 1 || grayLevel < 0 || grayLevel >255){
cout<<"Cannot get the size or gray level"<<endl;
f.close();
return;
}
//allocate data size
if( type==5){
wholeLength=width*height;
cout<<"width="<<width<<" height:"<<height<<endl;
}
if(type==6){
wholeLength=3*width*height;
cout<<"width="<<width<<" height:"<<height<<endl;
}
if(type==5 || type ==6){
//dataByte=new GLubyte[wholeLength];
dataByte=new unsigned char[wholeLength];
//f.read((char*)&dataByte[0], wholeLength);
//GLubyte j;
int w;
if(type==5)
w=width;
if(type==6)
w=3*width;
int count=0;int counth=0;
for(int i=height;i>0;i--){
for(int k=0;k<w;k++){
//j=(GLubyte)f.get();
//dataByte[(i-1)*w+k]=j;
f.read((char*)&dataByte[(i-1)*w+k],sizeof(unsigned char));
count++;
}
cout<<"count:"<<count<<endl;
count=0;
counth++;
}
cout<<"counth:"<<counth<<endl;
}
f.close();
}
int main(int argc, char *argv[] ) {
//string n;
//cout<<"Please enter the name of the image"<<endl;
//cin>>n;
readImage("small.ppm");
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB);
ori();
getChoice();
glutMainLoop();
return 0;
}
这是我的显示功能。他们可以显示PGM文件和PPM文件。
void drawAsType(char * d){
if(type==5){
glDrawPixels(width,height,GL_LUMINANCE,GL_UNSIGNED_BYTE,d);
glFlush();
glutSwapBuffers();
}
if(type==6 ){
glDrawPixels(width,height,GL_RGB,GL_UNSIGNED_BYTE,d);
glFlush();
glutSwapBuffers();
}
}
void changeSize(int w,int h){
glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0,(GLfloat)w,0.0,(GLfloat)h);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void display(void){
glClear(GL_COLOR_BUFFER_BIT);
glRasterPos2i(0,0);
glColor3f(1.0f,1.0f,1.0f);
drawAsType(dataByte);
}
void ori(){
glutInitWindowSize(width,height);
glutCreateWindow("Origin");
glutReshapeFunc(changeSize);
glutDisplayFunc(&display);
}
谁能帮我解决这个问题?
感谢 haraldK 的。
我发现原因是因为在 ignoreComent() 函数中我使用 peek() 来检查下一个字符是 '\n' 还是 '\t' 或 '#'。
void ignoreComment(ifstream &f){
char buf[1024];
char t;
while ( t=f.peek(),t=='\n'|| t=='\r'){
f.get();
}
if(t=='#'){
f.getline(buf,1023);
}
}
peek() 函数 returns 输入序列中的下一个字符,不提取它:该字符作为下一个要从流中提取的字符 .--表格 cplusplus.com
所以在最后一次调用peek() 之后检查garyLevel 的行。
ignoreComment(f);
由于garyLevel的第一个字符是'2',因为'2'不应该被忽略,所以程序执行下一行f >> grayLevel
然后执行读取图像数据部分。 But 流中的第一个字符是来自 peek() 的“2”。 所以我的数组 dataByte[]
的第一个字符将是 2 而不是真正的第一个字符图像块。
解决方法是替换'2'。所以我应该使用 f.get()
在我开始读取 RGB 数据之前再次。
所以只需在两个for循环之前添加f.get()
if(type==5 || type ==6){
dataByte=new char[wholeLength];
f.get(); /*ADD THIS GUY!*/
int w;
if(type==5)
w=width;
if(type==6)
w=3*width;
int count=0;int counth=0;
char t;
for(int i=height;i>0;i--){
for(int k=0;k<w;k++){
//read image RGB data
}
}