216 lines
6.1 KiB
JavaScript
216 lines
6.1 KiB
JavaScript
/**
|
|
* Module de préprocessing d'image pour améliorer l'OCR
|
|
* Optimisé pour les documents d'identité et CNI
|
|
*/
|
|
|
|
const sharp = require('sharp')
|
|
const fs = require('fs')
|
|
const path = require('path')
|
|
|
|
/**
|
|
* Prétraite une image pour améliorer la qualité de l'OCR
|
|
* @param {string} inputPath - Chemin vers l'image d'entrée
|
|
* @param {string} outputPath - Chemin vers l'image de sortie (optionnel)
|
|
* @param {Object} options - Options de préprocessing
|
|
* @returns {Promise<Buffer>} - Buffer de l'image préprocessée
|
|
*/
|
|
async function preprocessImageForOCR(inputPath, outputPath = null, options = {}) {
|
|
console.log(`[PREPROCESSING] Début du préprocessing de: ${path.basename(inputPath)}`)
|
|
|
|
try {
|
|
// Options par défaut optimisées pour les documents d'identité
|
|
const defaultOptions = {
|
|
// Redimensionnement
|
|
width: 2000, // Largeur cible
|
|
height: null, // Hauteur automatique (maintient le ratio)
|
|
|
|
// Amélioration du contraste
|
|
contrast: 1.5, // Augmente le contraste
|
|
brightness: 1.1, // Légère augmentation de la luminosité
|
|
|
|
// Filtres
|
|
sharpen: true, // Amélioration de la netteté
|
|
denoise: true, // Réduction du bruit
|
|
|
|
// Conversion
|
|
grayscale: true, // Conversion en niveaux de gris
|
|
threshold: null, // Seuil pour binarisation (optionnel)
|
|
|
|
// Format de sortie
|
|
format: 'png', // Format PNG pour meilleure qualité
|
|
quality: 100 // Qualité maximale
|
|
}
|
|
|
|
const config = { ...defaultOptions, ...options }
|
|
|
|
console.log(`[PREPROCESSING] Configuration:`, {
|
|
width: config.width,
|
|
contrast: config.contrast,
|
|
brightness: config.brightness,
|
|
grayscale: config.grayscale,
|
|
sharpen: config.sharpen
|
|
})
|
|
|
|
// Lecture de l'image
|
|
let image = sharp(inputPath)
|
|
|
|
// Redimensionnement
|
|
if (config.width || config.height) {
|
|
image = image.resize(config.width, config.height, {
|
|
fit: 'inside',
|
|
withoutEnlargement: false
|
|
})
|
|
console.log(`[PREPROCESSING] Redimensionnement appliqué`)
|
|
}
|
|
|
|
// Conversion en niveaux de gris
|
|
if (config.grayscale) {
|
|
image = image.grayscale()
|
|
console.log(`[PREPROCESSING] Conversion en niveaux de gris`)
|
|
}
|
|
|
|
// Amélioration du contraste et de la luminosité
|
|
if (config.contrast !== 1 || config.brightness !== 1) {
|
|
image = image.modulate({
|
|
brightness: config.brightness,
|
|
contrast: config.contrast
|
|
})
|
|
console.log(`[PREPROCESSING] Contraste (${config.contrast}) et luminosité (${config.brightness}) appliqués`)
|
|
}
|
|
|
|
// Amélioration de la netteté
|
|
if (config.sharpen) {
|
|
image = image.sharpen({
|
|
sigma: 1.0,
|
|
flat: 1.0,
|
|
jagged: 2.0
|
|
})
|
|
console.log(`[PREPROCESSING] Amélioration de la netteté appliquée`)
|
|
}
|
|
|
|
// Réduction du bruit
|
|
if (config.denoise) {
|
|
image = image.median(3)
|
|
console.log(`[PREPROCESSING] Réduction du bruit appliquée`)
|
|
}
|
|
|
|
// Binarisation (seuil) si demandée
|
|
if (config.threshold) {
|
|
image = image.threshold(config.threshold)
|
|
console.log(`[PREPROCESSING] Binarisation avec seuil ${config.threshold}`)
|
|
}
|
|
|
|
// Application des modifications et conversion
|
|
const processedBuffer = await image
|
|
.png({ quality: config.quality })
|
|
.toBuffer()
|
|
|
|
console.log(`[PREPROCESSING] Image préprocessée: ${processedBuffer.length} bytes`)
|
|
|
|
// Sauvegarde optionnelle
|
|
if (outputPath) {
|
|
await fs.promises.writeFile(outputPath, processedBuffer)
|
|
console.log(`[PREPROCESSING] Image sauvegardée: ${outputPath}`)
|
|
}
|
|
|
|
return processedBuffer
|
|
|
|
} catch (error) {
|
|
console.error(`[PREPROCESSING] Erreur lors du préprocessing:`, error.message)
|
|
throw error
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Prétraite une image avec plusieurs configurations et retourne la meilleure
|
|
* @param {string} inputPath - Chemin vers l'image d'entrée
|
|
* @returns {Promise<Buffer>} - Buffer de la meilleure image préprocessée
|
|
*/
|
|
async function preprocessImageMultipleConfigs(inputPath) {
|
|
console.log(`[PREPROCESSING] Test de plusieurs configurations pour: ${path.basename(inputPath)}`)
|
|
|
|
const configs = [
|
|
{
|
|
name: 'Standard',
|
|
options: {
|
|
width: 2000,
|
|
contrast: 1.5,
|
|
brightness: 1.1,
|
|
grayscale: true,
|
|
sharpen: true,
|
|
denoise: true
|
|
}
|
|
},
|
|
{
|
|
name: 'Haute résolution',
|
|
options: {
|
|
width: 3000,
|
|
contrast: 1.8,
|
|
brightness: 1.2,
|
|
grayscale: true,
|
|
sharpen: true,
|
|
denoise: false
|
|
}
|
|
},
|
|
{
|
|
name: 'Contraste élevé',
|
|
options: {
|
|
width: 2000,
|
|
contrast: 2.0,
|
|
brightness: 1.0,
|
|
grayscale: true,
|
|
sharpen: true,
|
|
denoise: true
|
|
}
|
|
},
|
|
{
|
|
name: 'Binarisation',
|
|
options: {
|
|
width: 2000,
|
|
contrast: 1.5,
|
|
brightness: 1.1,
|
|
grayscale: true,
|
|
sharpen: true,
|
|
denoise: true,
|
|
threshold: 128
|
|
}
|
|
}
|
|
]
|
|
|
|
// Pour l'instant, on utilise la configuration standard
|
|
// Dans une version avancée, on pourrait tester toutes les configs
|
|
const bestConfig = configs[0]
|
|
console.log(`[PREPROCESSING] Utilisation de la configuration: ${bestConfig.name}`)
|
|
|
|
return await preprocessImageForOCR(inputPath, null, bestConfig.options)
|
|
}
|
|
|
|
/**
|
|
* Analyse les métadonnées d'une image
|
|
* @param {string} imagePath - Chemin vers l'image
|
|
* @returns {Promise<Object>} - Métadonnées de l'image
|
|
*/
|
|
async function analyzeImageMetadata(imagePath) {
|
|
try {
|
|
const metadata = await sharp(imagePath).metadata()
|
|
console.log(`[PREPROCESSING] Métadonnées de ${path.basename(imagePath)}:`, {
|
|
format: metadata.format,
|
|
width: metadata.width,
|
|
height: metadata.height,
|
|
channels: metadata.channels,
|
|
density: metadata.density,
|
|
size: `${(metadata.size / 1024).toFixed(1)} KB`
|
|
})
|
|
return metadata
|
|
} catch (error) {
|
|
console.error(`[PREPROCESSING] Erreur lors de l'analyse des métadonnées:`, error.message)
|
|
return null
|
|
}
|
|
}
|
|
|
|
module.exports = {
|
|
preprocessImageForOCR,
|
|
preprocessImageMultipleConfigs,
|
|
analyzeImageMetadata
|
|
}
|