Iterating over jit.matrix

mrosenschein's icon

Hello

What I'm trying to do is very simple. It takes three lines in matlab. But I can't figure out how to do it in max.

I have a jit.matrix that holds a black and white picture. What I want to do is run over the rows of the matrix, from right to left, and when I hit a non-white cell, add the column coordinate of that cell to a list.

(The picture is a profile of a face, where the face is black and background white, and I'm trying to find the outline of the face).

How can I do this?

seejayjames's icon

[jit.iter] ?

Or the brute-force way, using [uzi] and the "getcell" message, holding the cell coordinates, and if the value is 0, bang the coordinates into your list. This "nested for-loop-approach" will be a lot slower than [jit.iter] though.

mrosenschein's icon

How exactly would you do it with iter? I need to jump to the next line every time I encounter a black pixel.

seejayjames's icon

You'd probably need to use the getcell approach if you have to conditionally jump to the next line.

Another idea is [jit.spill] and you can find the first black (0) element by using [zl filter 0] on the list. This will give you all the black pixels in the row and their indices, so you can keep additional ones if you want. [jit.spill] will be a lot faster than getcell too.

Wesley Smith's icon

There's no good solution for doing this kind of thing with standard Jitter objects. I wrote an object years ago to solve this exact problem. It's called xray.jit.cellcoords. You can download the objects here:

mrosenschein's icon

Thanks! This looks really helpful. I'm having trouble understanding the xray.jit.cellcoords help file, though. What exactly does this object do?

Wesley Smith's icon

It gives you the cell coordinates of all cells of the input matrix that are logic 1 (1 or 255 if it's char). For example a 1-plane float32 matrix that looks like

[0 1 0]
[1 0 0]
[0 0 1]

outputs a matrix:

[(1, 0), (0, 1), (2, 2)]

mrosenschein's icon

Okay, so it outputs a matrix of tuples? Or is it a two plane matrix?

I'm not sure I see how I could use such a matrix to find just the first white cell in each row...

mrosenschein's icon

Maybe the cellminmaxx object would be better? Can it be used to scan the matrix horizontally and find the first nonzero cell value in each row?

Alexis Baskind's icon

Hi mrosenschein,

If the resolution of the image is not too big I would do that by converting the matrix into a list using jit.spill. Then you have plenty of ways to get the indices corresponding to non-white cells, using the functions from the zl family, that also works for long lists, i.e. big images. But if the image has many pixels, using an external is the way to go.

Alexis

broc's icon

I think you could simply use [jit.iter] and [togedge] to detect zero/non-zero transitions.

Wesley Smith's icon

Another useful object if you're trying to get a silhouette is xray.jit.distance. You can pass in a binary mask to it and then threshold the result to get just the outline pixels. If you then piped that into xray.jit.cellcoords, you'd have a matrix with all of the outline pixel cell coordinates.

mrosenschein's icon

That's exactly what I need! Sorry for the n00bness but what exactly do you mean by "pass in a binary mask and then threshold the result"? Thanks for the help!

mrosenschein's icon

This patch that you (Wesley) posted in this thread https://cycling74.com/forums/making-a-vector-outline-from-a-silhouette looks very similar to what I'm trying to do. I just need to take it one more step and get a vector with the cell coordinates of the outline pixels. If you could explain how to do that using xray.jit.distance I would be over the moon :)

3584.silhouette.maxpat
Max Patch
mrosenschein's icon

Here's a picture as an example of what I'm going for. With Wesley's patch I can turn the girl's face into black and white outline. But I need to get rid of the white pixels inside the face (the eyes, for example), if I'm going to use jit.cellcoords to extract just the pixels that make up the silhouette.

3590.Screenshot20120323at9.43.05PM.png
png
Wesley Smith's icon
Max Patch
Copy patch and select New From Clipboard in Max.

Here's what I was thinking:

You'll probably need to use some cv.jit objects to fill in the area you want silhouetted. The basic idea is to color everything you want inside the shape white. You can then use jit.robcross or whatever to create the outline.

Wetterberg's icon

it would be great to be able to do the equivalent of [zl sub] with an object similar to jit.spill - gets all coordinates that are x in a normal max list, unlike jit.xray.cellcoord.

for my money [zl sub] is a great way to detect positions, and being able to apply this directly would be handy while reducing the number of big non-jitter lists flying around.

mrosenschein's icon

Hi Wesley,

I'm sorry to be so slow but I'm not sure I understand what the patch you posted does. I'm seeing three outputs: one that looks like edge detection of the image, one in grayscale and then the third is just black.

If I understand correctly what you're suggesting is to somehow fill in the face so that it will be all white and the use detection to extract just the silhouette line. That sounds great but I have no experience at all with the cv.jit objects...are there any in particular that could help me do that?

Thanks so much