Skip to content

Commit

Permalink
Merge pull request #152 from biigle/patch-2
Browse files Browse the repository at this point in the history
Handle large crops for feature vector generation
  • Loading branch information
mzur authored Feb 14, 2024
2 parents 32abe01 + 76cf0df commit 7143541
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 1 deletion.
23 changes: 22 additions & 1 deletion src/Jobs/ProcessAnnotatedImage.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,15 @@

class ProcessAnnotatedImage extends ProcessAnnotatedFile
{
/**
* Python PIL accepts images with at most 178956970 pixels. We set this arbitrary
* maximum dimension so the limit is not reached and feature vector computation
* does not consume a ridiculous amount of memory.
*
* @var int
*/
const CROP_MAX_EDGE_PX = 5000;

/**
* {@inheritdoc}
*/
Expand Down Expand Up @@ -125,9 +134,21 @@ protected function generateFeatureVectors(Collection $annotations, array|string
$box[2] -= $box[0];
$box[3] -= $box[1];

// The factor is <1 if the box is larger than the maximum size.
$factor = self::CROP_MAX_EDGE_PX / max($box[2], $box[3]);

$path = tempnam(sys_get_temp_dir(), 'largo_feature_vector_patch');
$tmpFiles[] = $path;
$image->crop(...$box)->pngsave($path);
$crop = $image->crop(...$box);

// Scale the crop and box to the maximum size.
if ($factor < 1) {
$crop = $crop->resize($factor);
$box[2] = intval($box[2] * $factor);
$box[3] = intval($box[3] * $factor);
}

$crop->pngsave($path);

$input[$path] = [$id => [0, 0, $box[2], $box[3]]];
}
Expand Down
44 changes: 44 additions & 0 deletions tests/Jobs/ProcessAnnotatedImageTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -726,6 +726,50 @@ public function testHandleFeatureVectorTiledImage()
$this->assertEquals([0, 0, 224, 224], $box);
}

public function testHandleFeatureVectorTiledImageLargePatch()
{
$vipsImage = $this->getImageMock(0);
$vipsImage->shouldReceive('crop')
->once()
->with(0, 0, 10000, 10000)
->andReturn($vipsImage);
$vipsImage->shouldReceive('resize')
->once()
->with(0.5)
->andReturn($vipsImage);
$vipsImage->shouldReceive('pngsave')->once()->andReturn($vipsImage);

$disk = Storage::fake('test');
$image = Image::factory()->create([
'attrs' => ['width' => 40000, 'height' => 40000],
'tiled' => true,
]);
$annotation = ImageAnnotationTest::create([
'points' => [0, 0, 10000, 0, 10000, 10000, 0, 10000, 0, 0],
'shape_id' => Shape::polygonId(),
'image_id' => $image->id,
]);
ImageAnnotationLabelTest::create(['annotation_id' => $annotation->id]);
$job = new ProcessAnnotatedImageStub($image,
skipPatches: true,
skipSvgs: true
);
$job->output = [[$annotation->id, '"'.json_encode(range(1, 384)).'"']];
$job->mock = $vipsImage;

$job->handle();
$prefix = fragment_uuid_path($annotation->image->uuid);
$this->assertEquals(1, ImageAnnotationLabelFeatureVector::count());

$input = $job->input;
$this->assertCount(1, $input);
$filename = array_keys($input)[0];
$this->assertArrayHasKey($annotation->id, $input[$filename]);
$box = $input[$filename][$annotation->id];
// These are the coordinates of the cropped image.
$this->assertEquals([0, 0, 5000, 5000], $box);
}

protected function getImageMock($times = 1)
{
$image = Mockery::mock();
Expand Down

0 comments on commit 7143541

Please sign in to comment.