scripts/hugin-gopro-fusion/main.ts

348 lines
12 KiB
TypeScript

/**
conversion de données gpx
conversion de données exif
Utilisation:
ts-node main.ts --goproMin=54903 --goproMax=56267 --goproSubFolder="INBOX_a_assembler/camaret1"
**/
const path = require('path');
// @ts-ignore
import * as fs from 'node:fs';
// @ts-ignore
import minimist from 'minimist';
let mini_arguments: any = minimist(process.argv.slice(2))
// configs
/**
* ces paramètres permettent de traiter par lots des assemblages sans avoir à scanner le dossier
*/
let gopro_fusion_separated_photos_folder = ''
let disable_pto_write = false;
// let previous_zero = '0'// numéro de photo gopro minimum front et back. correspond à GF080800.JPG + GB080800.JPG
let previous_zero = ''// numéro de photo gopro minimum front et back. correspond à GF080800.JPG + GB080800.JPG
let goproMin = 80800// numéro de photo gopro minimum front et back. correspond à GF080800.JPG + GB080800.JPG
let goproMax = 80801 // et maximum. correspond à GF080866.JPG + GB080866.JPG
let addExifToolInScript = true;
let base_gopro_folder = '/home/poule/encrypted/stockage-syncable/photos/imageries/gopro'
let outputStitchedFolder = base_gopro_folder + '/hugin_assemblages_script_output/'
if (mini_arguments['addExifToolInScript']) {
addExifToolInScript = mini_arguments['addExifToolInScript']
}
if (mini_arguments['goproMin']) {
goproMin = mini_arguments['goproMin']
}
if(goproMin < 100000){
previous_zero = '0'
}
if (mini_arguments['previous_zero']) {
previous_zero = '0'
}
console.log('# prise en compte du zéro? ', previous_zero)
if (mini_arguments['goproSubFolder']) {
gopro_fusion_separated_photos_folder = mini_arguments['goproSubFolder']
}
if (mini_arguments['goproMax']) {
goproMax = mini_arguments['goproMax']
}
let extension_photo_source = 'jpg'
extension_photo_source = 'JPG'
let gopro_folder = "/home/poule/encrypted/stockage-syncable/photos/imageries/gopro";
let dossier_pto_output = `/home/poule/encrypted/stockage-syncable/photos/imageries/gopro/INBOX_PTO_hugin`;
let absolutePath = `${gopro_folder}/${gopro_fusion_separated_photos_folder}`;
let folder = `${gopro_folder}/${gopro_fusion_separated_photos_folder}`
if (mini_arguments['folder']) {
folder = mini_arguments['folder']
}
let dossier_assemblages_output = `${gopro_folder}/hugin_assemblages_script_output`;
let minmax = findMinMaxNumberOfPhotos(folder)
console.log('# minmax', minmax)
goproMin = minmax.min
goproMax = minmax.max
let countPhotos = ((goproMax)) - ((goproMin));
console.log('# goproMax', goproMax)
console.log('# goproMin', goproMin)
console.log('# max - min', (goproMax) - (goproMin))
console.log('# la séquence', countPhotos, 'captures', (countPhotos / 60).toFixed(0), 'minutes');
console.log('# mini_arguments', mini_arguments)
/**
* trouver les valeux min et max de numéros de séquence gopro dans un dossier contenant des photos jpg
* @param dirPath
*/
function findMinMaxNumberOfPhotos(dirPath: string): { min: number, max: number } {
console.log('# dirPath', dirPath)
let minNumber: number = 0;
let maxNumber: number = 0;
// Boucler sur chaque fichier JPG dans le dossier
fs.readdirSync(dirPath).forEach(file => {
// Vérifier si le fichier est un fichier JPG
if (path.extname(file) === '.jpg' || path.extname(file) === '.JPG') {
// Éxtraire le nombre du nom de fichier
let matches: any = file.match(/(\d+)/);
if (matches && matches.length && matches[0]) {
let number = parseInt(matches[0]);
// Sauver le nombre minimal et maximal trouvé jusqu'à présent
if (minNumber === 0 && number > 0) {
minNumber = number;
}
if (number > maxNumber) {
maxNumber = number;
}
}
}
});
return {
min: minNumber,
max: maxNumber,
}
}
function makeBashScriptHugin(minmax: any) {
let count_pto_made_files =0;
// in each increment of a pair of photos, build a pto referencing absolute paths
// write the pto in output
console.log('# makeBashScriptHugin: parseInt(minmax.min)', parseInt(minmax.min))
console.log('# makeBashScriptHugin: gopro_fusion_separated_photos_folder', gopro_fusion_separated_photos_folder)
if (!disable_pto_write) {
console.log('# makeBashScriptHugin: début de l\'écriture des fichiers PTO')
}
for (let ii: any = parseInt(minmax.min); ii <= parseInt(
minmax.max
); ii++) {
let currentNumber = `${previous_zero}${ii}`;
let ptoContent = makePto(absolutePath, currentNumber);
let ptoFileName = `merging_${currentNumber}.pto`
let stitchedFileName = `assemblage_${currentNumber}`
let input_front_jpg = base_gopro_folder + '/' + gopro_fusion_separated_photos_folder + '/GF' + currentNumber + '.JPG'
let ptoPath = `${dossier_pto_output}/${ptoFileName}`
scriptsContent += '\n\n# capture n°' + currentNumber
scriptsContent +=
'\nif [ ! -f ' + outputStitchedFolder + stitchedFileName + '.jpg ]; then \n' +
// '\n echo ("assemblage à faire: ' + outputStitchedFolder + stitchedFileName + '.jpg") \n' +
'\n if [ -f ' + input_front_jpg + ' ]; then \n' +
' hugin_executor' +
' ' + ptoPath + ' ' +
'--stitching ' +
'--prefix=' + stitchedFileName +
'\n' +
// ' else' +
// '\n' +
// ' echo "le fichier assemblé '+stitchedFileName+' manque mais le fichier de caméra gopro front n\'existe pas."' +
'\n' +
// ' else' +
// '\n' +
// ' echo "le fichier assemblé '+stitchedFileName+' existe déjà"' +
'\n' +
' fi' +
'\n' +
'fi'
if (!disable_pto_write) {
writeFile(ptoFileName, ptoContent)
count_pto_made_files++;
}else{
console.log('# l écriture de fichiers PTO a été désactivée')
}
}
if (!disable_pto_write) {
console.log('# fin de l\'écriture des '+count_pto_made_files+' fichiers PTO')
}
let hugin_batch_command = 'bash /home/poule/encrypted/stockage-syncable/www/development/html/scripts/hugin-gopro-fusion/exif_batch.sh ' + goproMin + ' ' + goproMax + ' ' + gopro_fusion_separated_photos_folder
if (addExifToolInScript) {
scriptsContent += '\n # complétion des données gps depuis une des photos assemblées' +
'\n' + hugin_batch_command + '\n'
}
console.log('# ##############\n# pour lancer le script : \n', 'bash /home/poule/encrypted/stockage-syncable/photos/imageries/gopro/INBOX_PTO_hugin/hugin_executor_from_' + goproMin + '_to_' + goproMax + '.sh',
'\n' +
'\n # fusion des infos exif:' +
' bash /home/poule/encrypted/stockage-syncable/www/development/html/scripts/hugin-gopro-fusion/exif_batch.sh ' + goproMin + ' ' + goproMax + ' ' + gopro_fusion_separated_photos_folder,
'\n' +
'\n # déplacement en masse des fichiers assemblés:' +
' bash /home/poule/encrypted/stockage-syncable/www/development/html/scripts/hugin-gopro-fusion/move_batch.sh ' + goproMin + ' ' + goproMax + ' ' + gopro_fusion_separated_photos_folder,
'\n' +
'\n##############\n'
)
writeFile('hugin_executor_from_' + goproMin + '_to_' + goproMax + '.sh', scriptsContent);
}
/**
* génère un fichier pto sous forme de String
* @param absolutePath
* @param currentNumber
*/
function makePto(absolutePath: string, currentNumber: string):string {
let front_picture_name = absolutePath + '/GF' + currentNumber + '.' + extension_photo_source;
let back_picture_name = absolutePath + '/GB' + currentNumber + '.' + extension_photo_source;
// console.log('# front_picture_name', front_picture_name)
// console.log('# back_picture_name', front_picture_name)
return `
# hugin project file
#hugin_ptoversion 2
p f2 w5662 h2831 v360 k0 E12.9717 R0 n"TIFF_m c:LZW r:CROP"
m i0
# image lines
#-hugin autoCenterCrop=1 cropFactor=3.66667
i w3104 h3000 f2 v187.621680193473 Ra0.929120004177094 Rb-2.97991991043091 Rc0.832589983940125 Rd-1.6331000328064 Re0.223350003361702 Eev12.97168 Er1 Eb1 r0 p0 y0 TrX0 TrY0 TrZ0 Tpy0 Tpp0 j0 a0 b0 c0 d0 e0 g0 t0 Va1 Vb0 Vc0 Vd0 Vx0 Vy0 S56,3048,0,3000 Vm5 n"${back_picture_name}"
#-hugin autoCenterCrop=1 cropFactor=3.66666674613953
i w3104 h3000 f2 v200.312016860549 Ra0.929120004177094 Rb-2.97991991043091 Rc0.832589983940125 Rd-1.6331000328064 Re0.223350003361702 Eev12.86747 Er1 Eb1 r-0.321229885118998 p0.498637821558678 y-179.883320935885 TrX0 TrY0 TrZ0 Tpy0 Tpp0 j0 a0 b0 c0 d0 e0 g0 t0 Va1 Vb0 Vc0 Vd0 Vx0 Vy0 S56,3048,0,3000 Vm5 n"${front_picture_name}"
# specify variables that should be optimized
v v0
v Ra0
v Rb0
v Rc0
v Rd0
v Re0
v Vb0
v Vc0
v Vd0
v v1
v Ra1
v Rb1
v Rc1
v Rd1
v Re1
v Eev1
v r1
v p1
v y1
v Vb1
v Vc1
v Vd1
v
# control points
c n0 N1 x931 y224 X2196 Y185 t0
c n0 N1 x2488.00001630569 y524.000007066704 X514.860630764196 Y399.786974637271 t0
c n0 N1 x2863.00001478066 y830.000009619205 X310 Y843 t0
c n0 N1 x2912.00000631564 y1960.00001513932 X165.422047127648 Y1942.23480647153 t0
c n0 N1 x109.000013207601 y1959.00001112345 X2860.90269812833 Y1909.02844555244 t0
c n0 N1 x866.000016448824 y2711.00000028952 X2283.94256385574 Y2796.23681774024 t0
c n0 N1 x121.000003370916 y993.000018856411 X2832.23948711881 Y1047.9747652351 t0
# masks
k i0 t1 p"252 628 484 351 745 156 1008 41 1121 2 1992 4 2289 127 2571 317 2769 515 2949 795 3050 1087 3095 1282 3105 1673 3050 1932 2938 2213 2766 2482 2610 2646 2401 2803 2179 2917 1984 2985 1879 3006 1251 3011 1079 2970 815 2860 573 2706 385 2531 231 2328 106 2080 38 1859 -5 1600 -8 1311 80 969 109 878"
k i1 t1 p"252 628 484 351 745 156 1008 41 1121 2 1992 4 2289 127 2571 317 2769 515 2949 795 3050 1087 3095 1282 3105 1673 3050 1932 2925 2205 2766 2482 2610 2646 2401 2803 2179 2917 1984 2985 1879 3006 1251 3011 1079 2970 815 2860 573 2706 385 2531 231 2328 106 2080 38 1859 -5 1600 -8 1311 80 969 109 878"
#hugin_optimizeReferenceImage 0
#hugin_blender internal
#hugin_remapper nona
#hugin_enblendOptions
#hugin_enfuseOptions
#hugin_hdrmergeOptions -m avg -c
#hugin_verdandiOptions --seam=blend
#hugin_edgeFillMode 0
#hugin_edgeFillKeepInput false
#hugin_outputLDRBlended true
#hugin_outputLDRLayers false
#hugin_outputLDRExposureRemapped false
#hugin_outputLDRExposureLayers false
#hugin_outputLDRExposureBlended false
#hugin_outputLDRStacks false
#hugin_outputLDRExposureLayersFused false
#hugin_outputHDRBlended false
#hugin_outputHDRLayers false
#hugin_outputHDRStacks false
#hugin_outputLayersCompression LZW
#hugin_outputImageType jpg
#hugin_outputImageTypeCompression LZW
#hugin_outputJPEGQuality 90
#hugin_outputImageTypeHDR exr
#hugin_outputImageTypeHDRCompression LZW
#hugin_outputStacksMinOverlap 0.7
#hugin_outputLayersExposureDiff 0.5
#hugin_outputRangeCompression 0
#hugin_optimizerMasterSwitch 6
#hugin_optimizerPhotoMasterSwitch 21
`
}
function writeFile(fileName: string, fileContent: any) {
// console.log('# write file', dossier_pto_output , fileName)
return fs.writeFile(
`${dossier_pto_output}/${fileName}`,
fileContent,
'utf8',
(err) => {
if (err) {
console.log(`Error writing file: ${err}`)
}
}
)
}
let scriptsContent = `#!/bin/bash
echo "éxécuter tous les fichiers PTO dans : ${dossier_assemblages_output}"
cd ${dossier_assemblages_output}
pwd
`;
function main() {
makeBashScriptHugin({
min: goproMin,
max: goproMax,
})
}
// run it all
main()