add mono image -> many band column

or row ... handy for loading LUT images from CSV files
This commit is contained in:
John Cupitt 2015-06-04 16:02:41 +01:00
parent 5cb2239d7d
commit e84b97038f
3 changed files with 130 additions and 40 deletions

11
TODO
View File

@ -1,14 +1,11 @@
- try:
$ vips copy y.v x.v --width 1 --bands 3
VipsRegion: images do not match in pixel size
$ vips csvload ~/Desktop/NDVI_VGYRM-lut.txt x.v --skip 1
$ vips copy x.v x2.v --width 256 --height 1 --bands 4
Segmentation fault (core dumped)
copy will make 1xN or Nx1 M-band images into MxN one-band images, but it
won't go the other way
see commented-out test in test_conversion.py
- does ruby need to unpack RefString as well? what about C++?

View File

@ -49,6 +49,8 @@
* - use glib byteswap macros
* 15/5/15
* - support bands -> width conversion
* 4/6/15
* - support width -> bands conversion
*/
/*
@ -196,12 +198,14 @@ vips_copy_unbandize_gen( VipsRegion *or,
{
VipsRegion *ir = (VipsRegion *) seq;
VipsImage *in = ir->im;
VipsImage *out = or->im;
VipsRect *r = &or->valid;
VipsCopy *copy = (VipsCopy *) b;
SwapFn swap = vips_copy_swap_fn[copy->in->BandFmt];
int sze = VIPS_IMAGE_SIZEOF_ELEMENT( in );
VipsRect need;
int y;
int x, y;
/* Ask for input we need.
*/
@ -220,33 +224,97 @@ vips_copy_unbandize_gen( VipsRegion *or,
if( vips_region_prepare( ir, &need ) )
return( -1 );
/* We copy 1 pixel at a time. A vertical input image won't be
* guaranteed to have continuous data.
*/
for( y = 0; y < r->height; y++ ) {
VipsPel *p;
VipsPel *q;
for( x = 0; x < r->width; x++ ) {
VipsPel *p;
VipsPel *q;
if( in->Xsize == 1 ) {
p = r->left * VIPS_IMAGE_SIZEOF_ELEMENT( in ) +
VIPS_REGION_ADDR( ir, 0, r->top + y );
}
else {
p = r->left * VIPS_IMAGE_SIZEOF_ELEMENT( in ) +
VIPS_REGION_ADDR( ir, r->top + y, 0 );
}
q = VIPS_REGION_ADDR( or, r->left, r->top + y );
if( in->Xsize == 1 )
p = VIPS_REGION_ADDR( ir, 0, r->top + y ) +
(r->left + x) * sze;
else
p = VIPS_REGION_ADDR( ir, r->top + y, 0 ) +
(r->left + x) * sze;
q = VIPS_REGION_ADDR( or, r->left + x, r->top + y );
if( copy->swap &&
swap ) {
swap( p, q, r->width, copy->in );
if( copy->swap &&
swap )
swap( p, q, 1, out );
else
memcpy( q, p, sze );
}
}
return( 0 );
}
/* Copy, turning the x axis into bands, the inverse of the above. Useful for
* turning CSV files into RGB LUTs, for example.
*
* output has bands == input width, one of width or height 1.
*/
static int
vips_copy_bandize_gen( VipsRegion *or,
void *seq, void *a, void *b, gboolean *stop )
{
VipsRegion *ir = (VipsRegion *) seq;
VipsImage *in = ir->im;
VipsImage *out = or->im;
VipsRect *r = &or->valid;
VipsCopy *copy = (VipsCopy *) b;
SwapFn swap = vips_copy_swap_fn[copy->in->BandFmt];
int sze = VIPS_IMAGE_SIZEOF_ELEMENT( in );
VipsRect need;
int x, y;
/* Ask for input we need.
*/
if( out->Xsize == 1 ) {
need.left = 0;
need.top = r->top;
need.width = in->Xsize;
need.height = r->height;
}
else {
need.left = 0;
need.top = r->left;
need.width = in->Xsize;
need.height = r->width;
}
if( vips_region_prepare( ir, &need ) )
return( -1 );
/* We have to copy 1 pixel at a time. Each scanline in our input
* becomes a pixel in the output. Scanlines are not guaranteed to be
* continuous after vips_region_prepare(), they may be a window on a
* larger image.
*/
for( y = 0; y < r->height; y++ ) {
for( x = 0; x < r->width; x++ ) {
VipsPel *p;
VipsPel *q;
if( out->Xsize == 1 ) {
p = VIPS_REGION_ADDR( ir, 0, r->top + y );
q = VIPS_REGION_ADDR( or, 0, r->top + y );
}
else {
p = VIPS_REGION_ADDR( ir, 0, r->left + x );
q = VIPS_REGION_ADDR( or, 0, r->left + x );
}
if( copy->swap &&
swap )
swap( p, q, 1, out );
else
memcpy( q, p, out->Bands * sze );
}
else
/* We can't use vips_region_region(), it doesn't do
* coordinate transforms. If we want to avoid the
* memcpy() we'd need to add another vips_region_
* function.
*/
memcpy( q, p,
r->width * VIPS_IMAGE_SIZEOF_ELEMENT( in ) );
}
return( 0 );
@ -391,9 +459,18 @@ vips_copy_build( VipsObject *object )
conversion->out->Bands == 1 &&
conversion->out->Xsize == copy_of_fields.Bands &&
conversion->out->Ysize == VIPS_MAX(
copy_of_fields.Xsize, copy_of_fields.Ysize ) ) {
copy_of_fields.Xsize, copy_of_fields.Ysize ) )
copy_generate_fn = vips_copy_unbandize_gen;
}
/* And the inverse: change a MxN one-band image into a 1xN or Nx1
* M-band image. That is, squash M into bands.
*/
if( (conversion->out->Xsize == 1 || conversion->out->Ysize == 1) &&
conversion->out->Bands == copy_of_fields.Xsize &&
copy_of_fields.Bands == 1 &&
copy_of_fields.Ysize == VIPS_MAX(
conversion->out->Xsize, conversion->out->Ysize ) )
copy_generate_fn = vips_copy_bandize_gen;
if( vips_image_generate( conversion->out,
vips_start_one, copy_generate_fn, vips_stop_one,

View File

@ -224,16 +224,32 @@ class TestConversion(unittest.TestCase):
self.assertEqual(x.xoffset, 42)
x = self.colour.copy(yoffset = 42)
self.assertEqual(x.yoffset, 42)
x = self.colour.copy(bands = 1)
self.assertEqual(x.bands, 1)
x = self.colour.copy(format = Vips.BandFormat.USHORT, bands = 1)
self.assertEqual(x.format, Vips.BandFormat.USHORT)
x = self.colour.copy(coding = Vips.Coding.NONE)
self.assertEqual(x.coding, Vips.Coding.NONE)
x = self.colour.copy(width = 42)
self.assertEqual(x.width, 42)
x = self.colour.copy(height = 42)
self.assertEqual(x.height, 42)
# test squashing width of mono image into bands
x = self.mono.copy(width = 1, bands = self.mono.width)
self.assertEqual(x.width, 1)
self.assertEqual(x.bands, self.mono.width)
# back the other way
y = x.copy(width = self.mono.width, bands = 1)
self.assertEqual(y.width, self.mono.width)
self.assertEqual(y.bands, 1)
self.assertEqual(x.avg(), y.avg())
# test squashing width of mono image into bands
x = self.mono.copy(width = self.mono.height, height = 1, bands = self.mono.width)
self.assertEqual(x.width, self.mono.height)
self.assertEqual(x.height, 1)
self.assertEqual(x.bands, self.mono.width)
# back the other way
y = x.copy(width = self.mono.width, height = self.mono.height, bands = 1)
self.assertEqual(y.width, self.mono.width)
self.assertEqual(y.height, self.mono.height)
self.assertEqual(y.bands, 1)
#self.assertEqual(x.avg(), y.avg())
def test_embed(self):
for fmt in all_formats: