Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?

Feeding video data to Imager

by saintmike (Vicar)
on Mar 26, 2006 at 19:35 UTC ( #539316=perlquestion: print w/replies, xml ) Need Help??
saintmike has asked for the wisdom of the Perl Monks concerning the following question:

When feeding RGB (or, more accurately, BGR) data from a video source to Imager, a wise perlmonk once suggested to use this trick:
use Imager; my $i = Imager->new(); $nfr = reverse $nfr; $i->read( type => "pnm", data => "P6\n$width $height\n255\n" . $nfr ); $i->flip(dir => "hv");
Is this still the best way to do it? It seems awkward that the mighty Imager wouldn't allow feeding it RGB data directly.

Replies are listed 'Best First'.
Re: Feeding video data to Imager
by tonyc (Pilgrim) on Mar 27, 2006 at 00:01 UTC

    There's a few ways you could do it:

    • format the data as PPM as above, or perhaps raw would be better.
    • use the setscanline() method to write data a scanline at a time to the image. Unfortunately this expects data in a particular format, so you'll still need to adjust the data a bit.
    • # untested my $im = Imager->new(xsize=>$width, ysize=>$height); my $per_line = $width * 4; # adjust the data to the format setscanline() takes $nfr =~ s/(.)(.)(.)/$3$2$1\xFF/gs; # paint it for my $y (0..$height-1) { $im->setscanline(y=>$y, pixels => substr($nfr, $y * per_line, $per_line)); }
    • if performance is an issue you could use Inline::C or an XS module to reformat the data and draw it using i_plin() at the C level. Here's some Inline C code to do the job:
    • use Imager 0.48; # this assumes you've created an image of the right # size first. # if you call it with too large an image for the data # supplied then it will crash use Inline C => <<'EOS' => WITH => 'Imager'; void capture2image(Imager::ImgRaw out, unsigned char *data) { i_color *line_buf = mymalloc(sizeof(i_color) * out->xsize); i_color *pixelp; int x, y; for (y = 0; y < out->ysize; ++y) { pixelp = line_buf; for (x = 0; x < out->xsize; ++x) { pixelp->rgba.b = *data++; pixelp->rgba.g = *data++; pixelp->rgba.r = *data++; ++pixelp; } i_plin(out, 0, out->xsize, y, line_buf); } myfree(line_buf); } EOS

    Perhaps Imager needs a more general data to image method, but I haven't had much feedback on setscanline() and friends yet.

    Edit: added the Inline C code, hard to test without video capture data though.

Re: Feeding video data to Imager
by zentara (Archbishop) on Mar 27, 2006 at 12:37 UTC
    Is this still the best way to do it? It seems awkward that the mighty Imager wouldn't allow feeding it RGB data directly.

    I chose to do it that way, because I thought it was faster than the direct way which Imager allows, which is matrix transformation. Read "perldoc Imager::Transformations, where the following matrix method is shown

    # Swap red/green channel $new = $img->convert(matrix=>[ [ 0, 1, 0 ], [ 1, 0, 0 ], [ 0, 0, 1 ] ]);
    but, I think you will find that reversing is faster, although it will only work for swapping R and B, plus you need to invert it afterwards. But let us know, if you find otherwise.

    I'm not really a human, but I play one on earth. flash japh

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://539316]
Approved by Corion
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others having an uproarious good time at the Monastery: (4)
As of 2017-05-22 20:03 GMT
Find Nodes?
    Voting Booth?