license import { Keypoint } from './calculators/interfaces/common_interfaces' ; /** Karma server directory serving local files. */ export const KARMA_SERVER = './base/test_data' ; export async function loadImage ( imagePath , width , height ) { const img = new Image ( width , height ) ; const promise = new Promise < HTMLImageElement > ( ( resolve , reject ) => { img . crossOrigin = '' ; img . onload = ( ) => { resolve ( img ) ; } ; } ) ; img . src = `${ KARMA_SERVER }/${ imagePath }` ; return promise ; } param image param r param g param b return export function imageToBooleanMask ( rgbaData , r , g , b ) { const mask = [ ] ; for ( let i = 0 ; i < rgbaData . length ; i += 4 ) { mask . push ( rgbaData [ i ] >= r && rgbaData [ i + 1 ] >= g && rgbaData [ i + 2 ] >= b ) ; } return mask ; } param image param expectedMask param actualMask return export function segmentationIOU ( expectedMask , actualMask ) { expect ( expectedMask . length === actualMask . length ) ; const sum = ( mask ) => mask . reduce ( ( a , b ) => a + + b , 0 ) ; const intersectionMask = expectedMask . map ( ( value , index ) => value && actualMask [ index ] ) ; const iou = sum ( intersectionMask ) / ( sum ( expectedMask ) + sum ( actualMask ) - sum ( intersectionMask ) + Number . EPSILON ) ; return iou ; } export async function loadVideo ( videoPath , videoFPS , callback , expected , skeletonAdjacentPairs , simulatedInterval ) { let simulatedTimestamp ; let idx ; const actualInterval = 1 / videoFPS ; const video = document . createElement ( 'video' ) ; video . style . visibility = 'hidden' ; const source = document . createElement ( 'source' ) ; source . src = `${ KARMA_SERVER }/${ videoPath }` ; source . type = 'video/mp4' ; video . appendChild ( source ) ; document . body . appendChild ( video ) ; const canvas = document . createElement ( 'canvas' ) ; canvas . style . position = 'absolute' ; canvas . style . left = '0' ; canvas . style . top = '0' ; document . body . appendChild ( canvas ) ; const ctx = canvas . getContext ( '2d' ) ; const promise = new Promise < HTMLVideoElement > ( ( resolve , reject ) => { video . onseeked = async ( ) => { const keypoints = await callback ( video , simulatedTimestamp ) ; const expectedKeypoints = expected [ idx ] . map ( ( [ x , y ] ) => { return { x , y } ; } ) ; ctx . drawImage ( video , 0 , 0 ) ; draw ( expectedKeypoints , ctx , skeletonAdjacentPairs , 'Green' ) ; draw ( keypoints , ctx , skeletonAdjacentPairs , 'Red' ) ; const nextTime = video . currentTime + actualInterval ; if ( nextTime < video . duration ) { video . currentTime = nextTime ; simulatedTimestamp += simulatedInterval ; idx ++ ; } else { resolve ( video ) ; } } ; } ) ; video . onloadedmetadata = ( ) => { video . currentTime = 0.001 ; simulatedTimestamp = 0 ; idx = 0 ; const videoWidth = video . videoWidth ; const videoHeight = video . videoHeight ; video . width = videoWidth ; video . height = videoHeight ; canvas . width = videoWidth ; canvas . height = videoHeight ; } ; return promise ; } export function getXYPerFrame ( result ) { return result . map ( frameResult => { return frameResult . map ( keypoint => [ keypoint [ 0 ] , keypoint [ 1 ] ] ) ; } ) ; } function drawKeypoint ( keypoint , ctx ) { const circle = new Path2D ( ) ; circle . arc ( keypoint . x , keypoint . y , 4 , 0 , 2 * Math . PI ) ; ctx . fill ( circle ) ; ctx . stroke ( circle ) ; } function drawSkeleton ( keypoints , skeletonAdjacentPairs , ctx , color ) { ctx . fillStyle = color ; ctx . strokeStyle = color ; ctx . lineWidth = 2 ; for ( const pair of skeletonAdjacentPairs ) { const [ i , j ] = pair ; const kp1 = keypoints [ i ] ; const kp2 = keypoints [ j ] ; ctx . beginPath ( ) ; ctx . moveTo ( kp1 . x , kp1 . y ) ; ctx . lineTo ( kp2 . x , kp2 . y ) ; ctx . stroke ( ) ; } } function draw ( keypoints , ctx , skeletonAdjacentPairs , color ) { ctx . fillStyle = color ; ctx . strokeStyle = color ; for ( const keypoint of keypoints ) { drawKeypoint ( keypoint , ctx ) ; } drawSkeleton ( keypoints , skeletonAdjacentPairs , ctx , color ) ; }