face-landmarking-ios icon indicating copy to clipboard operation
face-landmarking-ios copied to clipboard

Rotate camera orientation

Open hoangdado opened this issue 7 years ago • 30 comments

I had tried to set the camera orientation to Landscape or Portrait but the below code (in DlibWrapper.mm) still return width = 640 and height = 480 (with preset is AVCaptureSessionPreset640x480). size_t width = CVPixelBufferGetWidth(imageBuffer); size_t height = CVPixelBufferGetHeight(imageBuffer); Then I couldn't do the landmark detection in Portrait view. Could you fix it?

hoangdado avatar Jul 28 '16 04:07 hoangdado

^bump

same issue, more or less. i updated my plist to show portrait w/ home button at bottom (normal orientation) and attached the result. the "face landmark mask" is drawn upright but, the camera feed is rotated landscape.

@zweigraf maybe you could find some time to document how the orientation gets determined/configured? I've rotated AVCaptureVideoPreviewLayer before but rotating AVSampleBufferDisplayLayer doesn't seem possible since i couldn't find examples off google.

img_3615

stanchiang avatar Aug 07 '16 01:08 stanchiang

@stanchiang I found that if you change the camera orientation to portrait or landscape the values still are width = 640 and height = 480. I think it maybe the camera hardware will alsway output the buffer with this size. What you can do is rotating the image when copying pixel value from CVPixelBuffer to dlib::array2ddlib::bgr_pixel. In addition you need to rotate the input face rect. I fixed the issue by doing that, but I got the performance problem. The doWorkOnSampleBuffer method consume too much CPU.

hoangdado avatar Aug 07 '16 02:08 hoangdado

can you add some sample code for your implementation? i was trying to do something like that but it wasn't working right.

stanchiang avatar Aug 07 '16 02:08 stanchiang

For copying pixel values:

    img.set_size(width, height);
    img.reset();
    long position = 0;

    while (img.move_next()) {
        lib::bgr_pixel& pixel = img.element();

        size_t row = position / height;
        size_t col = position % height;

        long bufferLocation = (col * width + row) * 4;

        char b = baseBuffer[bufferLocation];
        char g = baseBuffer[bufferLocation + 1];
        char r = baseBuffer[bufferLocation + 2];

        dlib:: bgr_pixel newpixel(b, g, r);
        pixel = newpixel;

        position++;
    }

For rotate face rect, I think you should code yourself for convenience. You only need to change the oneFaceRect.

hoangdado avatar Aug 07 '16 03:08 hoangdado

@hoangdado this code doesn't work for me, have you tested this ?

realmosn avatar Aug 08 '16 08:08 realmosn

Well, I also faced this problem. I didn't solve it but moved a little bit. Firstly, in the Target -> General: screen shot 2016-08-08 at 16 27 43

Next thing- 'SessionHandler.swift':

`func captureOutput(captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, fromConnection connection: AVCaptureConnection!) {

    connection.videoOrientation = AVCaptureVideoOrientation.Portrait

`

And the outcome is: img_0130

As you can see the landmarks are very distorted.

I hope someone will find it helpful and share the solution. :)

teresakozera avatar Aug 08 '16 15:08 teresakozera

@teresakozera I solved your problem. You only need to update convertScaleCGRect method as bellow:

    long right = (1.0 - rect.origin.y ) * size.width;
    long left = right - rect.size.height * size.width;
    long top = rect.origin.x * size.height;
    long bottom = top + rect.size.width * size.height;

@stanchiang You can follow this solution. It is much easier than that I recommend you before. View my fork project for source code https://github.com/hoangdado/face-landmarking-ios

Notice: With my fix, I don't know why the mouth landmarks is not exactly correct while the others is perfect!

hoangdado avatar Aug 08 '16 18:08 hoangdado

@hoangdado That fixed the issue, Thank you!
My issue is the landmarks are not so accurate for the mouth and around the face. were you able to fix it ?

realmosn avatar Aug 08 '16 19:08 realmosn

@hoangdado thanks that helped a lot!

I also had to do an affine transformation on the layer so that the output isn't mirrored the opposite way with:

    layer.setAffineTransform(CGAffineTransformMakeRotation(CGFloat(M_PI)))
    layer.setAffineTransform(CGAffineTransformScale(layer.affineTransform(), 1, -1))

stanchiang avatar Aug 09 '16 00:08 stanchiang

@hoangdado, thank you! it works perfect, no distortion- even in the mouth region. :)

previously I tried to manipulate convertScaleCGRect method, but I was scaling and changing the parameters instead of thinking of any kind of subtraction...

teresakozera avatar Aug 09 '16 08:08 teresakozera

@teresakozera for me the distorting is more of a stability issue when trying to maintain the tracking as the tolerance for difference angled faces seems to have gone down a bit for me when I try moving my face and the mask gets jittery.

Am I facing a different issue than you guys?

stanchiang avatar Aug 09 '16 09:08 stanchiang

@stanchiang I also observed this problem, but it also existed previously, with the ladndscape orientation. In my case it's not that big of an issue as I need it mostly in the direct position of the head towards camera. But I will also try to fix it- if I succeed I will certainly let you know. :)

teresakozera avatar Aug 09 '16 09:08 teresakozera

@teresakozera something off topic, could you please tell me how you got the landmarking lines working ? all I see in the app is the dots

thanks

realmosn avatar Aug 10 '16 18:08 realmosn

@ArtSebus probably just used the function dlib::draw_line(img, <#const point &p1#>, <#const point &p2#>, <#const pixel_type &val#>);

stanchiang avatar Aug 10 '16 18:08 stanchiang

@stanchiang could you please suggest what should I pass in for the parameters <#const point &p1#>, <#const point &p2#>, <#const pixel_type &val#>) Sorry I am not that good with C programming

realmosn avatar Aug 10 '16 18:08 realmosn

@ArtSebus haven't touched c in a few years myself haha. bit it looks like you's need to pass in a couple dlib::point that you want to connect and then specify what type of line you want to draw for the last one. I'd try inputing 3 for the value. No reason for that number, its just the same number that was used when drawing the dots in the existing code.

stanchiang avatar Aug 10 '16 18:08 stanchiang

@teresakozera trying something a little different right now. i'm storing shape.parts[60-67] which make up the mouth in a separate array and trying to pass it into UIKit/SceneKit to draw it separately.

[m addObject: [NSValue valueWithCGPoint:CGPointMake( [DlibWrapper pixelToPoints:p.x()], [DlibWrapper pixelToPoints:p.y()]) ]];

converting from pixels to points using this function https://gist.github.com/jordiboehmelopez/3168819

The problem it still seems stuck in the old bounds. sort of like the old screenshot i posted. I wasn't expecting this problem because we call convertCGRectValueArray before we loop through the shape.part array

stanchiang avatar Aug 10 '16 19:08 stanchiang

@ArtSebus line method, have a look at this: https://github.com/chili-epfl/attention-tracker/blob/master/README.md :)

@stanchiang - hmmm... a little bit odd. So with code from here and all the changes it works but when you try the above (a conversion from pixels to points) it displays landmarks in the other orientation? Does it happen after it is passed to UIKit or you check it before?

teresakozera avatar Aug 11 '16 08:08 teresakozera

@teresakozera - solved the transformation issue. is was my own fault. but now i noticed there is an issue where my cgpoint coordinates have a weird offset for some reason.

for example in my gamescene.swift file i had to add center = CGPointMake(center.x+50,center.y-100)

here's my code to show you what i mean https://github.com/stanchiang/face-landmarking-ios

stanchiang avatar Aug 11 '16 21:08 stanchiang

@stanchiang- I will have a look at it on Monday, as today I'm heading for a little bit longer weekend. Anyway I hope you manage to solve this problem earlier. :) Have a nice weekend!

teresakozera avatar Aug 12 '16 08:08 teresakozera

@hoangdado @stanchiang Thanks! I used your solution and almost all problems solved. Later, I found the better - just I think - way.

I made pull request: https://github.com/zweigraf/face-landmarking-ios/pull/9 . In this pr, I convert faceObject in SessionHandler for fitting the given orientation.

Even If connection's orientation is portrait, it works well.

How do you think??

morizotter avatar Aug 19 '16 05:08 morizotter

@teresakozera Could you suggest how to integrate attentionTracker into the project, I've tried for some time but still stuck and haven't got anywhere. almost close to pull my hairs out

realmosn avatar Aug 20 '16 09:08 realmosn

i want to crop landmarked portion of the face...... i want only the face can any one help me for this

Miths19 avatar May 06 '17 11:05 Miths19

@stanchiang You could easily change "VideoMirrored" mode with this one instead of doing some manual transforms if (connection.isVideoMirroringSupported) { connection.isVideoMirrored = true; }

trungnguyen1791 avatar Aug 14 '17 06:08 trungnguyen1791

@stanchiang I want to be able to support detection in both horizontal and vertical screens,can you provide sample demo ?

wangwenzhen avatar Oct 13 '17 03:10 wangwenzhen

bump I'm still having this issue on the latest master - setting my AVCaptureConnection videoOrientation to portrait causes all of the feature points to be wrong.

liamwalsh avatar Jun 22 '18 13:06 liamwalsh

@liamwalsh were you able to find a solution? I'm having the same problem as you.

Hardy143 avatar Jul 05 '18 15:07 Hardy143

@liamwalsh I found I was putting connection.videoOrientation = AVCaptureVideoOrientation.portrait in the wrong captureOutput function. It now works for me:

screen shot 2018-07-05 at 17 45 26

Hardy143 avatar Jul 05 '18 16:07 Hardy143

@stanchiang

First of thanks for your link. https://github.com/stanchiang/face-landmarking-ios

I have succesfully run your code but not have one issue that you face earlier may be offset where my cgpoint coordinates have a weird offset for some reason.

Here I am getting error:

validateTextureDimensions, line 759: error 'MTLTextureDescriptor has width (114046) greater than the maximum allowed size of 8192.' validateTextureDimensions:759: failed assertion `MTLTextureDescriptor has width (114046) greater than the maximum allowed size of 8192.'

can you please help me to come out.

Thanks

jpatel956 avatar Sep 14 '18 12:09 jpatel956

Hi, i'm dealing with this issue, and i'm not able to get it working in portrait mode. I've read all the threads here. My guess is that in portrait mode i'm having a wrong proportions of the layer where the wrapper draws the points on it because the points looks distorted. IMG-4956 IMG-4957

Can you please help me?

ScientistMe avatar Jul 17 '20 10:07 ScientistMe