Skip to content

Commit

Permalink
refactored
Browse files Browse the repository at this point in the history
  • Loading branch information
alexlevy0 committed Dec 2, 2023
1 parent 00765b5 commit 926b34f
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 74 deletions.
24 changes: 17 additions & 7 deletions amplify/backend/function/S3Trigger52a3ac74/lib/config.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,26 @@
import { EQuality } from './types'

export const conf = {
rekognitionWidth: 1920,
rekognitionHeight: 1080,
// rekognition: true,
rekognition: false,
rekognitionConf: {
enabled: false,
region: 'eu-west-2',
bucketSufix: '-london',
width: 1920,
height: 1080,
highConfidenceThreshold: 95.0,
paddingFactorBase: 1,
significantMovementThreshold: 0.7,
jobCheckDelay: 5000,
minShotDuration: 0.6,
confidenceThreshold: 85.0,
cropChangeTolerance: 0.6,
},
debug: false,
quality: EQuality.LOW,
// quality: EQuality.HIGH,
region: 'eu-west-3',
nameModifier: '_edited',
batchModifier: '_batch_',
// quality: EQuality.HIGH,
quality: EQuality.LOW,
debug: false,
targetWidth: 360,
targetHeight: 640,
batchSize: 5,
Expand Down
24 changes: 3 additions & 21 deletions amplify/backend/function/S3Trigger52a3ac74/lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import { Handler } from 'aws-lambda'
import * as fs from 'fs/promises'
import { processVideo } from './video'
import { download, upload } from './s3'
import { getData } from './getData'
import StatusUploader from './StatusUploader'
import { EStatus, LambdaS3Event, IShot } from './types'
import { EStatus, LambdaS3Event } from './types'
import { cleanTempFiles } from './utils'
import { conf } from './config'
import { analyzeVideo } from './rekognition'

export const handler: Handler = async (event: LambdaS3Event) => {
Expand All @@ -22,25 +20,9 @@ export const handler: Handler = async (event: LambdaS3Event) => {
objectKey: objKey,
} = await getData(event)

let shots: IShot[]

if (conf.rekognition) {
const _shots = await analyzeVideo(
objKey,
`${bK}-london`,
conf.rekognitionWidth,
conf.rekognitionHeight,
)
console.log('_shots before', _shots.length);
shots = _shots.filter(s => s.ts_end !== s.ts_start)
console.log('shots after', shots.length);
} else {
const cropData = JSON.parse(await fs.readFile(conf.cropFile, 'utf-8'))
shots = cropData.shots
}

const shotsData = await analyzeVideo(objKey, bK)
await download(bK, objKey, tmpFP)
await processVideo(tmpFP, outputFP, shots)
await processVideo(tmpFP, outputFP, shotsData)
await upload(outputFP, bK, newKey)
await cleanTempFiles(tmpFP, outputFP)
await statusUploader.setStatus(EStatus.Succeded)
Expand Down
83 changes: 37 additions & 46 deletions amplify/backend/function/S3Trigger52a3ac74/lib/rekognition.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import * as fs from 'fs/promises'
import {
RekognitionClient,
StartFaceDetectionCommand,
Expand All @@ -7,32 +8,9 @@ import {
BoundingBox,
Emotion,
} from '@aws-sdk/client-rekognition'

const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms))

const config = {
highConfidenceThreshold: 95.0,
paddingFactorBase: 1,
significantMovementThreshold: 0.7,
jobCheckDelay: 5000,
}
const MIN_SHOT_DURATION = 0.6
const CONFIDENCE_THRESHOLD = 85.0
const CROP_CHANGE_TOLERANCE = 0.6 // Seuil de tolérance pour le changement de crop (20%)

interface CropCoordinates {
x: number
y: number
w: number
h: number
}

interface VideoShot {
ts_start: number
ts_end: number
crop: CropCoordinates
label: string | null
}
import { conf } from './config'
import { sleep } from './utils'
import { CropCoordinates, VideoShot } from './types'

async function waitForJobCompletion(
client: RekognitionClient,
Expand All @@ -50,7 +28,7 @@ async function waitForJobCompletion(
throw new Error('Job failed')
}

await delay(config.jobCheckDelay)
await sleep(conf.rekognitionConf.jobCheckDelay)
}
throw new Error('Job did not complete successfully')
}
Expand All @@ -62,15 +40,15 @@ function calculateCropCoordinates(
lastFacePosition: BoundingBox | null,
lastCrop: CropCoordinates | null,
): CropCoordinates {
let paddingFactor = config.paddingFactorBase
let paddingFactor = conf.rekognitionConf.paddingFactorBase

if (lastFacePosition) {
const movementX = Math.abs(box.Left - lastFacePosition.Left)
const movementY = Math.abs(box.Top - lastFacePosition.Top)

if (
movementX > config.significantMovementThreshold ||
movementY > config.significantMovementThreshold
movementX > conf.rekognitionConf.significantMovementThreshold ||
movementY > conf.rekognitionConf.significantMovementThreshold
) {
paddingFactor = paddingFactor + 0.5
}
Expand Down Expand Up @@ -114,7 +92,8 @@ function calculateCropCoordinates(
function isSignificantEmotionChange(
prevEmotions: Emotion[],
newEmotions: Emotion[],
highConfidenceThreshold: number = config.highConfidenceThreshold,
highConfidenceThreshold: number = conf.rekognitionConf
.highConfidenceThreshold,
): boolean {
if (
!prevEmotions ||
Expand Down Expand Up @@ -149,34 +128,40 @@ function isSignificantEmotionChange(
function isCropChangeSignificant(
newCrop: CropCoordinates,
lastCrop: CropCoordinates,
tolerance: number = conf.rekognitionConf.cropChangeTolerance,
): boolean {
const deltaX = Math.abs(newCrop.x - lastCrop.x)
const deltaY = Math.abs(newCrop.y - lastCrop.y)
const deltaW = Math.abs(newCrop.w - lastCrop.w)
const deltaH = Math.abs(newCrop.h - lastCrop.h)

return (
deltaX > CROP_CHANGE_TOLERANCE * lastCrop.w ||
deltaY > CROP_CHANGE_TOLERANCE * lastCrop.h ||
deltaW > CROP_CHANGE_TOLERANCE * lastCrop.w ||
deltaH > CROP_CHANGE_TOLERANCE * lastCrop.h
deltaX > tolerance * lastCrop.w ||
deltaY > tolerance * lastCrop.h ||
deltaW > tolerance * lastCrop.w ||
deltaH > tolerance * lastCrop.h
)
}

export async function analyzeVideo(
Name: string,
Bucket: string,
videoWidth: number,
videoHeight: number,
videoWidth: number = conf.rekognitionConf.width,
videoHeight: number = conf.rekognitionConf.height,
): Promise<VideoShot[]> {
if (!conf.rekognitionConf.enabled) {
const cropData = JSON.parse(await fs.readFile(conf.cropFile, 'utf-8'))
return cropData.shots
}

const client = new RekognitionClient({
region: 'eu-west-2',
region: conf.rekognitionConf.region,
})

const startCommand = new StartFaceDetectionCommand({
Video: {
S3Object: {
Bucket,
Bucket: `${Bucket}${conf.rekognitionConf.bucketSufix}`,
Name,
},
},
Expand All @@ -202,7 +187,7 @@ export async function analyzeVideo(

const shouldCrop =
face &&
face.Confidence >= CONFIDENCE_THRESHOLD &&
conf.rekognitionConf.confidenceThreshold &&
(face.MouthOpen?.Value ||
face.Smile?.Value ||
isSignificantEmotionChange(prevEmotions, face.Emotions))
Expand All @@ -227,7 +212,10 @@ export async function analyzeVideo(
lastShot.ts_end = Math.max(lastShot.ts_end, timestamp)
} else {
let newTsStart = lastShot.ts_end
let newTsEnd = Math.max(newTsStart + MIN_SHOT_DURATION, timestamp)
let newTsEnd = Math.max(
newTsStart + conf.rekognitionConf.minShotDuration,
timestamp,
)
shots.push({
ts_start: newTsStart,
ts_end: newTsEnd,
Expand All @@ -239,7 +227,7 @@ export async function analyzeVideo(
// Premier shot
shots.push({
ts_start: 0,
ts_end: Math.max(MIN_SHOT_DURATION, timestamp),
ts_end: Math.max(conf.rekognitionConf.minShotDuration, timestamp),
crop,
label: shouldCrop ? 'Speaking/Smiling' : 'No Face',
})
Expand All @@ -248,12 +236,15 @@ export async function analyzeVideo(
lastFacePosition = face ? face.BoundingBox : lastFacePosition
prevEmotions = face ? face.Emotions : prevEmotions
})
// Assurer que le dernier shot a une durée minimale de MIN_SHOT_DURATION
// Assurer que le dernier shot a une durée minimale de conf.rekognitionConf.minShotDuration
if (shots.length > 0) {
let lastShot = shots[shots.length - 1]
if (lastShot.ts_end - lastShot.ts_start < MIN_SHOT_DURATION) {
lastShot.ts_end = lastShot.ts_start + MIN_SHOT_DURATION
if (
lastShot.ts_end - lastShot.ts_start <
conf.rekognitionConf.minShotDuration
) {
lastShot.ts_end = lastShot.ts_start + conf.rekognitionConf.minShotDuration
}
}
return shots
return shots.filter(s => s.ts_end !== s.ts_start)
}
15 changes: 15 additions & 0 deletions amplify/backend/function/S3Trigger52a3ac74/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,21 @@ export interface S3Record {
}
}


export interface CropCoordinates {
x: number
y: number
w: number
h: number
}

export interface VideoShot {
ts_start: number
ts_end: number
crop: CropCoordinates
label: string | null
}

export enum EQuality {
HIGH,
LOW,
Expand Down
3 changes: 3 additions & 0 deletions amplify/backend/function/S3Trigger52a3ac74/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,6 @@ export async function cleanTempFiles(tmpFP: string, outputFP: string) {

export const decodeS3Key = (key: string) =>
decodeURIComponent(key.replace(/\+/g, ' '))

export const sleep = (ms: number) =>
new Promise(resolve => setTimeout(resolve, ms))

0 comments on commit 926b34f

Please sign in to comment.