Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Database Migration for sorting images: #352

Merged
merged 40 commits into from
Jul 21, 2021
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
45c0952
Add Database Migration for sorting images:
jLeonBi May 31, 2021
2ede036
Add python scripts:
jLeonBi Jun 1, 2021
bf46a0c
Add empty jobs and associated test:
jLeonBi Jun 2, 2021
79a303c
Work on GenerateImageHash:
jLeonBi Jun 8, 2021
53b992f
Fill SimilarityIndex Job and script:
jLeonBi Jun 9, 2021
e6a1898
Change chack if hash is available
jLeonBi Jun 9, 2021
b7babf7
add install imagehash but Failed
jLeonBi Jun 15, 2021
daeb7dc
change install from imagehash to suggested one
jLeonBi Jun 15, 2021
c3a7edd
Fix worker dockerfile
mzur Jun 15, 2021
6d10209
rewrite GenerateHashValueJob:
jLeonBi Jun 15, 2021
820d235
Merge branch 'imageCompare' of https://github.com/jLeonBi/core into i…
jLeonBi Jun 15, 2021
9891b7e
rewrite generateHashValue:
jLeonBi Jun 16, 2021
f9db386
Change HashValueGenerator script:
jLeonBi Jun 16, 2021
19f6b86
work on generateHashValue job:
jLeonBi Jun 21, 2021
918f33c
Fix first time handle job:
jLeonBi Jun 21, 2021
5656448
update python scripts:
jLeonBi Jun 21, 2021
c5a955b
change output file form SamilarityIndexGenerator:
jLeonBi Jun 21, 2021
7d4aefa
add GerneatSimilarityIndex Job:
jLeonBi Jun 22, 2021
8e94659
update GenerateHashValue and GenerateSimilarityIndex:
jLeonBi Jun 24, 2021
973d06d
rewrite GenerateSimilartiyIndex:
jLeonBi Jun 24, 2021
65768e5
Add starting Jobs:
jLeonBi Jun 25, 2021
ceb76b4
apply suggested changes from mzur
jLeonBi Jun 25, 2021
2b69863
Merge branch 'master' of https://github.com/biigle/core into imageCom…
mzur Jun 28, 2021
e5fd021
Merge for starting docker and add boarder case:
jLeonBi Jun 29, 2021
1631983
Apply code readable suggestions:
jLeonBi Jun 30, 2021
af0714f
change npmrc for pushing
jLeonBi Jul 11, 2021
d871422
remove old token
jLeonBi Jul 11, 2021
2e5a4d0
add new token
jLeonBi Jul 11, 2021
85aa868
remove npmrc
jLeonBi Jul 11, 2021
2f6a01a
Delete .npmrc
jLeonBi Jul 11, 2021
48fa4ed
empty npmrc
jLeonBi Jul 11, 2021
69d71c4
remove old npmrc add new one
jLeonBi Jul 11, 2021
7da371d
Work on Frontend for Similarity Index Sorting:
jLeonBi Jul 12, 2021
3932686
remove unneccessary dd
jLeonBi Jul 12, 2021
d0a14f8
run npm run prod
jLeonBi Jul 12, 2021
bebb618
Work on similarityindex sorter:
jLeonBi Jul 14, 2021
87d1dc5
update sorting function for similarity index
jLeonBi Jul 17, 2021
b947b68
Add test for SimilarityIndexController:
jLeonBi Jul 17, 2021
90ce456
add crated for getting volume id
jLeonBi Jul 20, 2021
2e5c4d7
Finsish image compare project:
jLeonBi Jul 21, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .docker/worker.dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,14 @@ RUN apk add --no-cache --virtual .build-deps \
python3-dev \
py3-pip \
py3-wheel \
py3-numpy-dev \
build-base \
libjpeg-turbo-dev \
libpng-dev \
&& pip3 install --no-cache-dir \
PyExcelerate==0.6.7 \
Pillow==8.1.* \
imagehash \
&& apk del --purge .build-deps \
&& rm -rf /var/cache/apk/*

Expand Down
241 changes: 241 additions & 0 deletions app/Jobs/GenerateHashValue.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
<?php

namespace Biigle\Jobs;




use Biigle\Image;
use Biigle\Jobs\Job;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Exception;
use App;
use Log;
use Storage;
use FileCache;
use File;

class GenerateHashValue extends Job implements ShouldQueue
{
use SerializesModels, InteractsWithQueue;

/**
* The number of times the job may be attempted.
*
* @var int
*/
public $tries = 2;

/**
* Ignore this job if the image does not exist any more.
*
* @var bool
*/
protected $deleteWhenMissingModels = true;


/**
* The image to process
*
* @var Image
*/
public $image;

/**
* The hash value according to the image
*
* @var string
*/
public $hash;

/**
* Caches if an image needs a new hash value.
*
* @var array
*/
protected $needsHashCache;


/**
* Create a new job instance.
*
* @param Image $image The image to generate process.
*
* @return void
*/
public function __construct(Image $image)
{
$this->image = $image;
$this->hash = '';
$this->needsHashCache = [];
}

/**
* Execute the job.
*
* @return void
* @throws Exception
*/
public function handle()
{
$hashValue = $this->getHashValue($this->image);
if ($hashValue !== null) {
$this->image->hash = $hashValue["hash"];
$this->image->save();
}
}

/**
* Gets a thumbnail for a single image.
*
* @param Image $image
* @return string byte string of the image
*/
protected function getThumbnail(Image $image)
{
try {
$prefix = fragment_uuid_path($image->uuid);
$format = config('thumbnails.format');

return Storage::disk(config('thumbnails.storage_disk'))
->get("{$prefix}.{$format}");
} catch (Exception $e) {
// File not found
return false;
}

}

/**
* Execute the HashValueGenerator and get the resulting hash value to the image.
*
* @param Image $image
* @return string
* @throws Exception
*/
protected function getHashValue(Image $image)
{
$imageByteString = $this->getThumbnail($image);
if ($imageByteString !== false) {
$script = config('biigle.hash_value_generator');

try {
$outputPath = $this->getOutputJsonPath($image);
$inputPath = $this->createInputJson($image, $imageByteString);
$output = $this->python("{$script} {$inputPath} {$outputPath}");
$hashValue = $this->decodeOutputJson($outputPath);
} catch (Exception $e) {
$input = File::get($inputPath);
throw new Exception("Input: {$input}\n" . $e->getMessage());
} finally {
if (isset($inputPath)) {
$this->maybeDeleteFile($inputPath);
}

if (isset($outputPath)) {
$this->maybeDeleteFile($outputPath);
}
}
return $hashValue;
} else {
// Return null if no hash can be computed
return null;
}
}



/**
* Execute a Python script.
*
* @param $command
* @return string the hash value for the image
* @throws Exception
*/
protected function python($command)
{
$lines = 0;
$code = 0;
$python = config('biigle.python');


exec("{$python} {$command}", $lines, $code);

if ($code !== 0) {
throw new Exception("Error while executing Python script':\n".implode("\n", $lines));
}

return end($lines);

}

/**
* Get the path to to input file for the object tracking script.
*
* @param Image $image
*
* @return string
*/
protected function getInputJsonPath(Image $image)
{
return config('hash.tmp_dir')."/generate_hash_value_input_{$image->id}.json";
mzur marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* Create the JSON file that is the input for the HashValueGenerator script.
*
* @param Image $image
* @param string $imagePath Path to the video file.
*
* @return string Path to the JSON file.
*/
protected function createInputJson(Image $image, $imageAsByteString)
{
$path = $this->getInputJsonPath($image);
$content = json_encode([
'image_as_byte_string' => $imageAsByteString,
mzur marked this conversation as resolved.
Show resolved Hide resolved
'image_id' => $image->id,
]);

File::put($path, $content);
mzur marked this conversation as resolved.
Show resolved Hide resolved
return $path;
}

/**
* Get the path to to output file for the object tracking script.
*
* @param Image $image
*
* @return string
*/
protected function getOutputJsonPath(Image $image)
{
return config('hash.tmp_dir')."/generate_hash_value_output_{$image->id}.json";
mzur marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* @param path Opens the ouput path after the python script and decodes it
*
* @return mixed
*/
protected function decodeOutputJson($path)
{
return json_decode(File::get($path), true);

}


/**
* Delete a file if it exists.
*
* @param string $path
*/
protected function maybeDeleteFile($path)
{
if (File::exists($path)) {
File::delete($path);
}
}
}
104 changes: 104 additions & 0 deletions app/Jobs/GenerateSimilarityIndex.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<?php

namespace Biigle\Jobs;


use Biigle\Jobs\Job;
use Biigle\Volume;
use Storage;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;


class GenerateSimilarityIndex extends Job implements ShouldQueue
{
use SerializesModels, InteractsWithQueue;

/**
* The number of times the job may be attempted.
*
* @var int
*/
public $tries = 2;

/**
* Ignore this job if the image does not exist any more.
*
* @var bool
*/
protected $deleteWhenMissingModels = true;


/**
* The volume to process
*
* @var Volume
*/
public $volume;

/**
* The hash values according to the images in volume
*
* @var array
*/
protected $hashValues;

/**
* The similarity values according to the images in volume
*
* @var array
*/
protected $similarityIndices;

/**
* Create a new job instance.
*
* @param Image $image The image to generate process.
*
* @return void
*/
public function __construct(Volume $volume)
{
$this->volume = $volume;
$this->hashValues = [];
$this->similarityIndices = [];

}

/**
* Execute the job.
*
* @return void
*/
public function handle()
{
$query = $this->volume->files();

}

/**
* Execute a Python script.
*
* @param
*
* @return
*/
protected function python($inputPath, $outputPath)
{
$lines = 0;
$code = 0;
$python = config('biigle.python');


exec("{$python} {$inputPath} {$outputPath}", $lines, $code);

if ($code !== 0) {
throw new Exception("Error while executing Python script':\n".implode("\n", $lines));
}

return end($lines);


}
}
1 change: 1 addition & 0 deletions app/Jobs/TrackObject.php
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ protected function getTrackingKeyframes(VideoAnnotation $annotation)
$outputPath = $this->getOutputJsonPath($annotation);
$output = $this->python("{$script} {$inputPath} {$outputPath}");
$keyframes = json_decode(File::get($outputPath), true);
dd($output);
mzur marked this conversation as resolved.
Show resolved Hide resolved
} catch (Exception $e) {
$input = File::get($inputPath);
throw new Exception("Input: {$input}\n".$e->getMessage());
Expand Down
20 changes: 20 additions & 0 deletions config/biigle.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,24 @@
'cache_key' => env('BIIGLE_FEDERATED_SEARCH_CACHE_KEY', 'federated_search_index'),
],

/*
| Path to the Python executable.
*/
'python' => '/usr/bin/python3',

/*
| Directory where temporary files should be stored.
*/
'tmp_dir' => env('HASH_TMP_DIR', sys_get_temp_dir()),

/*
| Path to the HashValueGenerator.
*/
'hash_value_generator' => __DIR__.'/../resources/scripts/HashValueGenerator.py',

/*
| Path to the SimilarityIndexGenerator.
*/
'similarity_index_generator' => __DIR__.'/../resources/scripts/SimilarityIndexGenerator.py',

];
Loading