c语言查看pbm图片,图像格式PPM/PGM/PBM剖析及代码实现 -- 视频和图像编程基础之一...

可移植像素图格式 PPM,灰度图格式 PGM,位图格式 PBM 的介绍

简介

可移植像素图格式(PPM),可移植灰度图格式(PGM)和可移植位图格式(PBM)是便于跨平台的图像格式。有时候也被统称为 PNM 格式

文件格式描述

这三种格式其实是一样的描述方法,只不过 PBM 是单色,PGM 是灰度图,PPM 使用 RGB 颜色。

每个文件的开头两个字节(ASCII 码)作为文件描述符,指出具体格式和编码形式。

Type

Magic number

Extension

Colors

ASCII

Binary

Portable BitMap

P1

P4

.pbm

0–1 (white & black)

Portable GrayMap

P2

P5

.pgm

0–255 (gray scale)

Portable PixMap

P3

P6

.ppm

0–255 (RGB)

Portable Arbitrary Map

P7

.pam

0–255 (RGB_ALPHA)

格式例子

PBM

注意每行结束有换行符

P1

# This is an example bitmap of the letter "J"

6 10

0 0 0 0 1 0

0 0 0 0 1 0

0 0 0 0 1 0

0 0 0 0 1 0

0 0 0 0 1 0

0 0 0 0 1 0

1 0 0 0 1 0

0 1 1 1 0 0

0 0 0 0 0 0

0 0 0 0 0 0

上面的图像是一个J

PGM

P2

# Shows the word "FEEP" (example from Netpbm man page on PGM)

24 7

15

0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

0 3 3 3 3 0 0 7 7 7 7 0 0 11 11 11 11 0 0 15 15 15 15 0

0 3 0 0 0 0 0 7 0 0 0 0 0 11 0 0 0 0 0 15 0 0 15 0

0 3 3 3 0 0 0 7 7 7 0 0 0 11 11 11 0 0 0 15 15 15 15 0

0 3 0 0 0 0 0 7 0 0 0 0 0 11 0 0 0 0 0 15 0 0 0 0

0 3 0 0 0 0 0 7 7 7 7 0 0 11 11 11 11 0 0 15 0 0 0 0

0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

上面的图像是

1460000016443601?w=220&h=64

PPM

P3

3 2

255

# The part above is the header

# "P3" means this is a RGB color image in ASCII

# "3 2" is the width and height of the image in pixels

# "255" is the maximum value for each color

# The part below is image data: RGB triplets

255 0 0 0 255 0 0 0 255

255 255 0 255 255 255 0 0 0

把上面六个像素放大后显示如下

1460000016443602?w=192&h=128

PAM

P7

WIDTH 4

HEIGHT 2

DEPTH 4

MAXVAL 255

TUPLTYPE RGB_ALPHA

ENDHDR

0000FFFF 00FF00FF FF0000FF FFFFFFFF

0000FF7F 00FF007F FF00007F FFFFFF7F

上面数据放大显示如下:

1460000016443603?w=214&h=135

用go生成PPM文件

下面是简单的ppm包

package ppm

import (

"fmt"

"io"

"os"

)

// WriteTo outputs 8-bit P6 PPM format to an io.Writer.

func (b *Bitmap) WritePpmTo(w io.Writer) (err error) {

// magic number

if _, err = fmt.Fprintln(w, "P6"); err != nil {

return

}

// comments

for _, c := range b.Comments {

if _, err = fmt.Fprintln(w, c); err != nil {

return

}

}

// x, y, depth

_, err = fmt.Fprintf(w, "%d %d\n255\n", b.cols, b.rows)

if err != nil {

return

}

// raster data in a single write

b3 := make([]byte, 3*len(b.px))

n1 := 0

for _, px := range b.px {

b3[n1] = px.R

b3[n1+1] = px.G

b3[n1+2] = px.B

n1 += 3

}

if _, err = w.Write(b3); err != nil {

return

}

return

}

// WriteFile writes to the specified filename.

func (b *Bitmap) WritePpmFile(fn string) (err error) {

var f *os.File

if f, err = os.Create(fn); err != nil {

return

}

if err = b.WritePpmTo(f); err != nil {

return

}

return f.Close()

}

下面是生成ppm的程序

package main

// Files required to build supporting package raster are found in:

// * This task (immediately above)

// * Bitmap task

import (

"raster"

"fmt"

)

func main() {

b := raster.NewBitmap(400, 300)

b.FillRgb(0x240008) // a dark red

err := b.WritePpmFile("write.ppm")

if err != nil {

fmt.Println(err)

}

}

用C生成PPM文件

#include

int main()

{

const char *filename = "n.pgm";

int x, y;

/* size of the image */

const int x_max = 100; /* width */

const int y_max = 100; /* height */

/* 2D array for colors (shades of gray) */

unsigned char data[y_max][x_max];

/* color component is coded from 0 to 255 ; it is 8 bit color file */

const int MaxColorComponentValue = 255;

FILE * fp;

/* comment should start with # */

const char *comment = "# this is my new binary pgm file";

/* fill the data array */

for (y = 0; y < y_max; ++y) {

for (x = 0; x < x_max; ++x) {

data[y][x] = (x + y) & 255;

}

}

/* write the whole data array to ppm file in one step */

/* create new file, give it a name and open it in binary mode */

fp = fopen(filename, "wb");

/* write header to the file */

fprintf(fp, "P5\n %s\n %d\n %d\n %d\n", comment, x_max, y_max,

MaxColorComponentValue);

/* write image data bytes to the file */

fwrite(data, sizeof(data), 1, fp);

fclose(fp);

printf("OK - file %s saved\n", filename);

return 0;

}

或者

imglib.h

#ifndef _IMGLIB_0

#define _IMGLIB_0

#include

#include

#include

#include

#include

#include

typedef unsigned char color_component;

typedef color_component pixel[3];

typedef struct {

unsigned int width;

unsigned int height;

pixel * buf;

} image_t;

typedef image_t * image;

image alloc_img(unsigned int width, unsigned int height);

void free_img(image);

void fill_img(image img,

color_component r,

color_component g,

color_component b );

void put_pixel_unsafe(

image img,

unsigned int x,

unsigned int y,

color_component r,

color_component g,

color_component b );

void put_pixel_clip(

image img,

unsigned int x,

unsigned int y,

color_component r,

color_component g,

color_component b );

#define GET_PIXEL(IMG, X, Y) (IMG->buf[ ((Y) * IMG->width + (X)) ])

#endif

imglib.c

image alloc_img(unsigned int width, unsigned int height)

{

image img;

img = malloc(sizeof(image_t));

img->buf = malloc(width * height * sizeof(pixel));

img->width = width;

img->height = height;

return img;

}

void free_img(image img)

{

free(img->buf);

free(img);

}

void fill_img(

image img,

color_component r,

color_component g,

color_component b )

{

unsigned int i, n;

n = img->width * img->height;

for (i=0; i < n; ++i)

{

img->buf[i][0] = r;

img->buf[i][1] = g;

img->buf[i][2] = b;

}

}

void put_pixel_unsafe(

image img,

unsigned int x,

unsigned int y,

color_component r,

color_component g,

color_component b )

{

unsigned int ofs;

ofs = (y * img->width) + x;

img->buf[ofs][0] = r;

img->buf[ofs][1] = g;

img->buf[ofs][2] = b;

}

void put_pixel_clip(

image img,

unsigned int x,

unsigned int y,

color_component r,

color_component g,

color_component b )

{

if (x < img->width && y < img->height)

put_pixel_unsafe(img, x, y, r, g, b);

}

output_ppm

#include "imglib.h"

void output_ppm(FILE *fd, image img)

{

unsigned int n;

(void) fprintf(fd, "P6\n%d %d\n255\n", img->width, img->height);

n = img->width * img->height;

(void) fwrite(img->buf, sizeof(pixel), n, fd);

(void) fflush(fd);

}

生成raw rgb格式

其实raw rgb和ppm数据是一样的,我们生成出300帧的ppm数据,然后送给ffplayer(ffmpeg)来播放

下面是我的go代码:

//

// Created by : Harris Zhu

// Filename : genrgb.go

// Author : Harris Zhu

// Created On : 2018-09-14 02:13:11

// Last Modified : 2018-09-14 02:13:11

// Update Count : 1

// Tags :

// Description :

// Conclusion :

//

//=======================================================================

package main

import (

"bufio"

"os"

"strconv"

"time"

"github.com/urfave/cli"

)

func main() {

app := cli.NewApp()

app.Name = "genrgb"

app.Version = "1.0.0"

app.Compiled = time.Now()

app.Authors = []cli.Author{

cli.Author{

Name: "Harris Zhu",

Email: "zhuzhzh@163.com",

},

}

app.Usage = "svpaser "

name := "rgb.data"

w := 600

h := 480

f := 20

app.Action = func(c *cli.Context) error {

name = c.Args().Get(0)

w, _ = strconv.Atoi(c.Args().Get(1))

h, _ = strconv.Atoi(c.Args().Get(2))

f, _ = strconv.Atoi(c.Args().Get(3))

genrgb(name, w, h, f)

return nil

}

app.Run(os.Args)

}

func genrgb(filepath string, w int, h int, f int) {

fout, err := os.Create(filepath)

defer fout.Close()

if err != nil {

panic(err)

}

bufout := bufio.NewWriter(fout)

// bufout.WriteString("P6\n # this is my ppm file\n")

// bufout.WriteString(strconv.Itoa(w))

// bufout.WriteString("\n")

// bufout.WriteString(strconv.Itoa(h))

// bufout.WriteString("\n")

// bufout.WriteString(strconv.Itoa(255))

// bufout.WriteString("\n")

r := []byte{255, 0, 0}

g := []byte{0, 255, 0}

b := []byte{0, 0, 255}

dcnt := 0

//k: frame

//i: height column

//j: width line

for k := 0; k < f; k++ {

for i := 0; i < h; i++ {

//fmt.Println("hline: ", i)

for j := 0; j < w; j++ {

if k%3 == 0 {

bufout.Write(r)

dcnt++

} else if k%3 == 1 {

bufout.Write(g)

dcnt++

} else if k%3 == 2 {

bufout.Write(b)

dcnt++

}

//fmt.Println("vline: ", j)

}

}

bufout.Flush()

//fmt.Printf("total pixels = %d\n", dcnt)

}

}

下面是makefile:

FILE = genrgb

GENFILE = rgb.data

b build:

go build -gcflags "-N -l" $(FILE).go

g gen:

./$(FILE) $(GENFILE) 60 40 300

p play:

cat $(GENFILE) | ffplay -i pipe:0 -f rawvideo -pix_fmt rgb24 -video_size 60x40

依次执行make b; make g; make p可以看到下面的播放视频

1460000016443604?w=62&h=78

它交替显示红绿蓝

总结

RGB比较直观的图像显示方法,但相对YUV来说比较占空间,每个像素占用3个byte, 像1080P的图像就要占用$1920*1080*3=6,220,800byte$, 但它用于作为图像和显示入门是非常好的。能够让你很快就常会编程显示图像。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值