-
Notifications
You must be signed in to change notification settings - Fork 25
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
BodySegmentation: Add raw values of the detected body parts to result #139
Conversation
for (let x=0; x < video.width; x += gridSize) { | ||
for (let y=0; y < video.height; y += gridSize) { | ||
// torsoFront is e.g. 12 | ||
if (segmentation.values[y * video.width + x] == 12) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will do a more detailed review later, but a quick idea! What about we add some time of enum
constants as part of BodySegmentation
? so the code could read:
if (segmentation.values[y * video.width + x] == BodySegmentation.RIGHT_FACE) {
or would this make more sense?
if (segmentation.values[y * video.width + x] == ml5.RIGHT_FACE) {
@ziyuan-linn is there anything in other models like this as precedent?
The numbers and names from BodyPix can be in the tfjs-models repo.
(This is important info for the documentation page! cc @MOQN @QuinnHe @alanvww @myrahsa, sorry for so many tags, not sure who is working on this particular model docs!)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thinking that makes a lot of sense for {read,use}ability!
One caveat would that we'd be baking the internals of a particular model in the API, where even tf's BodySegmentation is trying (albeit not very successfully) to keep the interface agnostic... so maybe rather BodySegmentation.RIGHT_FACE
, and perhaps those properties only get added with the BodyPix model (and not the SelfieSegmentation one)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yes, that makes sense! Would something like BodyPix.RIGHT_FACE
help make it more clear? We could also put strings into the array or something instead of integers but that might get tricky to maintain and be prone to error with mispellings, etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would this be BodySegmentation.BodyPix.RIGHT_FACE
? Or ml5.BodyPix.RIGHT_FACE
? (both seem a bit like a mouthful imho 🤔)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, haha, no I think we should only do one of these:
BodySegmentation.RIGHT_FACE
ml5.RIGHT_FACE
BodyPix.RIGHT_FACE
While there could be other models that have different integer values for similar or the same parts later, I think it's ok to leave that for a problem another day?
I might opt for ml5.RIGHT_FACE
it's both the fewest characters and also implies that this is something we are doing above and beyond the model's native behavior itself?
I'm not sure! Open to any and all ideas!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I implemented the BodySegmentation.torsoFront
avenue for testing below, if anyone wants to give it a spin.
The properties currently get added to the instance whenever the BodyPix model is loaded. In practice this means that one would access it through the user-defined name of the instance variable - which could be short, e.g. just body
. No strong opinions either way (also noticing that my JavaScript is quite rusty... please feel welcome to solve this more elegantly).
As for naming: I've been reusing the data from the existing BODYPIX_PALETTE.js
file, which has it camel-case. The file isn't used for anything else (anymore), so we could easily change it e.g. to TORSO_FRONT
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using enum
constants is a great idea!! I would vote for BodyPix.RIGHT_FACE
. I will elaborate on it in the following comment.
2cc07f6
to
dea5395
Compare
@gohai thank you so much for implementing this and sorry for my delayed response! It looks great and I have one minor suggestion. How about we call them this way?
|
dea5395
to
e3253f2
Compare
Thanks @MOQN for this great suggestion. I pushed the change. Curious: would you think there is a reason to expose
|
I believe we can also apply Also Thus, I vote for
|
I think it's good to have! It can be used for a super quick demo. I remember that TensorFlow's BodyPix's |
I like this proposal from @MOQN! |
I am not sure what the proper way is to expose additional top-level objects. ( |
Ah, right, the proper way to do this is in fact ml5.BodyPix.RIGHT_FACE
ml5.MoveNet.LEFT_WRIST
// etc. Otherwise, yes, we can consider adding more keywords to the global namespace? |
An alternative could be adding it to the instance object after loading a specific model. It's slightly less explicit than your and Moon's suggested top-level class for each model:
or, if we were to rename the (example) instance variables after the actual model used
|
Sorry for the late response! The only current model with a similar behavior is BodyPose. The skeleton info is returned by the let bodyPose;
function preload() {
bodyPose = ml5.bodyPose();
}
function setup() {
connections = bodyPose.getSkeleton();
} If we want to keep it consistent, we could have a let bodySegmentation;
let rightWristId;
function preload() {
bodySegmentation = ml5.bodySegmentation();
}
function setup() {
rightWristId = bodySegmentation.getPartsId().RIHGT_WRIST;
} The I don't think adding any global variable is a good idea since it might clash with user-defined globals, especially if they are model names. I'm pretty sure setting ml5.BodyPix = {};
ml5.BodyPix.RIGHT_WRIST = 5 I don't think this is a good idea either since having the object on I would vote for adding the enums somewhere on the instance object. |
6687ce5
to
75a5bb4
Compare
I cleaned up and tested this series. The only open questions imho are whether the constants should be behind some |
src/BodySegmentation/index.js
Outdated
|
||
// add constants to the instance variable | ||
this.BACKGROUND = 0; | ||
this.PERSON = 255; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@MOQN Prefer BODY
?
Thank you @ziyuan-linn for adding your thoughts, it all makes sense to me! I like the way the examples currently look and though I can see the value of a If including an explicit call to a method is important for maintenance and consistency across models, I might suggest writing the examples something along the lines of (seeing how just let bodyParts = bodySegmentation.partsIDs();
function draw() {
background(255);
image(video, 0, 0);
if (segmentation) {
let gridSize = 10;
for (let x=0; x < video.width; x += gridSize) {
for (let y=0; y < video.height; y += gridSize) {
if (segmentation.data[y * video.width + x] == bodyParts.TORSO_FRONT) {
fill(255, 0, 0);
noStroke();
circle(x, y, gridSize);
}
}
}
}
} Thank you so much @gohai I think we should include this if we can for this week's release! |
As suggested by @MOQN.
This information is static, and we'll be offering a more convenient way of accessing it.
This is done when the specific model is being loaded.
This renames bodyPix to bodySegmentation, as spotted by @MOQN. It also assigns the entire result to a global variable, which makes it more obvious which member we're accessing during drawing.
75a5bb4
to
2698c3b
Compare
@ziyuan-linn Since there is so much (frantic) development activity at the moment, let me go ahead and merge this one now. We can still explore a |
@MOQN brought this up during our meeting today: He
suggestedrequested to have some way of accessing the raw values (detected class ids per pixel) - so that so that the users of the library don't have to derive those from the color values of the (multi-colored) mask.I sketched out two options here - but I'd think we should only pick one (or none) of them:
.values
: an array of numbers, one per pixel of the input image.valuesImageData
: the image data as the the tf model is returning it (this has the value stored in the red channel, so one would want to look at only every fourth entry in the array)Open questions:
@shiffman @ziyuan-linn @MOQN 🙏