tfjs icon indicating copy to clipboard operation
tfjs copied to clipboard

`tfjs-models/face-landmarks-detection`: `keypoint` `291` missing in `MEDIAPIPE_FACE_MESH_KEYPOINTS_BY_CONTOUR.lips`

Open jackbdu opened this issue 11 months ago • 2 comments

System information

  • Have I written custom code (as opposed to using a stock example script provided in TensorFlow.js): No
  • OS Platform and Distribution (e.g., Linux Ubuntu 16.04): macOS Sonoma 14.4
  • Mobile device (e.g. iPhone 8, Pixel 2, Samsung Galaxy) if the issue happens on mobile device: n/a
  • TensorFlow.js installed from (npm or script link): n/a
  • TensorFlow.js version (use command below): n/a
  • Browser version: Firefox Developer Edition 125.0b3 (64-bit)
  • Tensorflow.js Converter Version: n/a

Describe the current behavior keypoint 291 (a corner of the lips, see mesh_map) is not present in MEDIAPIPE_FACE_MESH_KEYPOINTS_BY_CONTOUR.lips

Describe the expected behavior keypoint 291 should be included in MEDIAPIPE_FACE_MESH_KEYPOINTS_BY_CONTOUR.lips

Standalone code to reproduce the issue Lips corner not rendered correctly in face-landmarks-detection MediaPipe demo

Other info / logs I suspect the issue comes from constants.ts. See snippets below:

lips: connectionsToIndices(LIPS_CONNECTIONS),
function connectionsToIndices(connections: PairArray) {
  const indices = connections.map(connection => connection[0]);
  indices.push(connections[connections.length - 1][1]);
  return indices;
}
const LIPS_CONNECTIONS: PairArray = [
  [61, 146],  [146, 91],  [91, 181],  [181, 84],  [84, 17],   [17, 314],
  [314, 405], [405, 321], [321, 375], [375, 291], [61, 185],  [185, 40],
  [40, 39],   [39, 37],   [37, 0],    [0, 267],   [267, 269], [269, 270],
  [270, 409], [409, 291], [78, 95],   [95, 88],   [88, 178],  [178, 87],
  [87, 14],   [14, 317],  [317, 402], [402, 318], [318, 324], [324, 308],
  [78, 191],  [191, 80],  [80, 81],   [81, 82],   [82, 13],   [13, 312],
  [312, 311], [311, 310], [310, 415], [415, 308],
];

In particular, connections.map(connection => connection[0]); eliminates keypoint 291 from the indices. This happens because 291 appears as the second element in both [375, 291] and [409, 291] whereas 61 (the other corner of the lips) appears as the first element in both [61, 146] and [61, 185].

Hope this helps!

jackbdu avatar Mar 23 '24 22:03 jackbdu

There are two other keypoints which will be missing for the same reason.

Part: lips is missing indices: 291
Part: leftEye is complete.
Part: leftEyebrow is missing indices: 285
Part: leftIris is complete.
Part: rightEye is complete.
Part: rightEyebrow is missing indices: 55
Part: rightIris is complete.
Part: faceOval is complete.

It seems like the expectation is that the end of one pair will be the start of the next pair, so I ran a quick code to find instances where this is not the case. Not all of these "jumps" lead to missing indices. For the left/right eye the index which would potentially be left off (362/ 133) also appears at the end of the last connection so it gets included there. Same for index 308 in the lips.

Part: lips
Connection jump at index 10: 291 -> 61 between pairs [375,291] and [61,185].
Connection jump at index 20: 291 -> 78 between pairs [409,291] and [78,95].
Connection jump at index 30: 308 -> 78 between pairs [324,308] and [78,191].
Part: leftEye
Connection jump at index 8: 362 -> 263 between pairs [382,362] and [263,466].
Part: leftEyebrow
Connection jump at index 4: 285 -> 300 between pairs [295,285] and [300,293].
Part: leftIris
All okay
Part: rightEye
Connection jump at index 8: 133 -> 33 between pairs [155,133] and [33,246].
Part: rightEyebrow
Connection jump at index 4: 55 -> 70 between pairs [65,55] and [70,63].
Part: rightIris
All okay
Part: faceOval
All okay

Code I used for both checks:

const parts = {
  lips: LIPS_CONNECTIONS,
  leftEye: LEFT_EYE_CONNECTIONS,
  leftEyebrow: LEFT_EYEBROW_CONNECTIONS,
  leftIris: LEFT_IRIS_CONNECTIONS,
  rightEye: RIGHT_EYE_CONNECTIONS,
  rightEyebrow: RIGHT_EYEBROW_CONNECTIONS,
  rightIris: RIGHT_IRIS_CONNECTIONS,
  faceOval: FACE_OVAL_CONNECTIONS,
};

Object.entries(parts).forEach(([part, connections]) => {
  const allIndices = MEDIAPIPE_FACE_MESH_KEYPOINTS_BY_CONTOUR[part];
  const omissions = connections
    .flat()
    .filter((index) => !allIndices.includes(index));
  if (omissions.length > 0) {
    console.log(`Part: ${part} is missing indices: ${omissions.join(", ")}`);
  } else {
    console.log(`Part: ${part} is complete.`);
  }
});

Object.entries(parts).forEach(([part, connections]) => {
  const jumps = connections
    .map((current, i) => {
      const previous = connections[i - 1];
      if (previous && current[0] !== previous[1]) {
        return `Connection jump at index ${i}: ${previous[1]} -> ${current[0]} between pairs [${previous}] and [${current}].`;
      }
      return;
    })
    .filter(Boolean);
  console.log(`Part: ${part}`);
  if (jumps.length > 0) {
    console.log(jumps.join("\n"));
  } else {
    console.log("All okay");
  }
});

lindapaiste avatar Mar 25 '24 22:03 lindapaiste

Hi, @jackbdu, @lindapaiste

We sincerely apologize for the delay in our response and thank you for bringing this issue to our attention, I tried face-landmarks-detection MediaPipe demo and it seems like there are total 03 missing keypoints so our relavant team will look into this issue and I believe they'll fix this issue soon

In the meantime, we welcome contributions from the community. If you have a solution to address these missing keypoints, please feel free to submit a pull request (PR). Our team will thoroughly review your PR and take appropriate action, including merging it if it meets our guidelines.

Thank you for your cooperation and patience.

gaikwadrahul8 avatar Apr 16 '24 19:04 gaikwadrahul8