0

AVFoundationを使用して、ビデオフレームをキャプチャし、opencvで処理して、新しいiPadのUIImageViewに結果を表示しています。opencvプロセスは次のことを行います(「inImg」はビデオフレームです):

cv::Mat testROI = inImg.rowRange(0,100);
testROI = testROI.colRange(0,10);
testROI.setTo(255); // this is a BGRA frame.

ただし、フレームの左上隅に垂直の白いバー(100行x 10列)を表示する代わりに、右上隅から左下に向かってそれぞれ10ピクセルの長さの階段のような水平線を100本取得しました。

調べてみると、表示されているフレームの幅がcv::Matより8ピクセル広いように見えることがわかりました。(つまり、2行目の9番目のピクセルは1行目の1番目のピクセルのすぐ下にあります。)

ビデオフレーム自体が正しく表示されます(行間のずれはありません)。この問題は、AVCaptureSession.sessionPresetがAVCaptureSessionPresetMedium(frame rows = 480、cols = 360)の場合に発生しますが、AVCaptureSessionPresetHigh(frame rows = 640、cols = 480)の場合は発生しません。

フルスクリーンで表示される360列があります。(トラバースしてcv :: Matをピクセルごとに変更してみました。ピクセル1-360が正しく表示されました。361-368が消え、369がピクセル1の真下に表示されました)。

imageview.contentMode(UIViewContentModeScaleAspectFillとUIViewContentModeScaleAspectFit)とimageview.clipsToBound(YES / NO)の組み合わせを試しましたが、うまくいきませんでした。

何が問題なのですか?どうもありがとうございます。

次のコードを使用してAVCaptureSessionを作成します。

NSArray* devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];

if ([devices count] == 0) {
    NSLog(@"No video capture devices found");
    return NO;
}


for (AVCaptureDevice *device in devices) {
     if ([device position] == AVCaptureDevicePositionFront) {
           _captureDevice = device;
     }
}


NSError* error_exp = nil;
if ([_captureDevice lockForConfiguration:&error_exp]) {
    [_captureDevice setWhiteBalanceMode:AVCaptureWhiteBalanceModeContinuousAutoWhiteBalance];
    [_captureDevice unlockForConfiguration];
}
// Create the capture session
_captureSession = [[AVCaptureSession alloc] init];
_captureSession.sessionPreset = AVCaptureSessionPresetMedium;


// Create device input
NSError *error = nil;
AVCaptureDeviceInput *input = [[AVCaptureDeviceInput alloc] initWithDevice:_captureDevice error:&error];

// Create and configure device output
_videoOutput = [[AVCaptureVideoDataOutput alloc] init];

dispatch_queue_t queue = dispatch_queue_create("cameraQueue", NULL); 
[_videoOutput setSampleBufferDelegate:self queue:queue];
dispatch_release(queue); 

_videoOutput.alwaysDiscardsLateVideoFrames = YES; 

OSType format = kCVPixelFormatType_32BGRA;

_videoOutput.videoSettings = [NSDictionary dictionaryWithObject:[NSNumber numberWithUnsignedInt:format]forKey:(id)kCVPixelBufferPixelFormatTypeKey];


// Connect up inputs and outputs
if ([_captureSession canAddInput:input]) {
    [_captureSession addInput:input];
}

if ([_captureSession canAddOutput:_videoOutput]) {
    [_captureSession addOutput:_videoOutput];
}

AVCaptureConnection * captureConnection = [_videoOutput connectionWithMediaType:AVMediaTypeVideo];

if (captureConnection.isVideoMinFrameDurationSupported)
    captureConnection.videoMinFrameDuration = CMTimeMake(1, 60);
if (captureConnection.isVideoMaxFrameDurationSupported)
    captureConnection.videoMaxFrameDuration = CMTimeMake(1, 60);

if (captureConnection.supportsVideoMirroring)
    [captureConnection setVideoMirrored:NO];

[captureConnection setVideoOrientation:AVCaptureVideoOrientationPortraitUpsideDown];

フレームを受信すると、次のように呼び出されます。

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection
{
@autoreleasepool {

    CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
    OSType format = CVPixelBufferGetPixelFormatType(pixelBuffer);
    CGRect videoRect = CGRectMake(0.0f, 0.0f, CVPixelBufferGetWidth(pixelBuffer), CVPixelBufferGetHeight(pixelBuffer));

    AVCaptureConnection *currentConnection = [[_videoOutput connections] objectAtIndex:0];

    AVCaptureVideoOrientation videoOrientation = [currentConnection videoOrientation];
    CGImageRef quartzImage;

    // For color mode a 4-channel cv::Mat is created from the BGRA data
    CVPixelBufferLockBaseAddress(pixelBuffer, 0);
    void *baseaddress = CVPixelBufferGetBaseAddress(pixelBuffer);

    cv::Mat mat(videoRect.size.height, videoRect.size.width, CV_8UC4, baseaddress, 0);

    if ([self doFrame]) { // a flag to switch processing ON/OFF
            [self processFrame:mat videoRect:videoRect videoOrientation:videoOrientation];  // "processFrame" is the opencv function shown above
    }

    CIImage *ciImage = [CIImage imageWithCVPixelBuffer:pixelBuffer];
    quartzImage = [self.context createCGImage:ciImage fromRect:ciImage.extent];
    CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);

    UIImage *image = [UIImage imageWithCGImage:quartzImage scale:1.0 orientation:UIImageOrientationUp];

    CGImageRelease(quartzImage);

    [self.imageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:YES];
4

1 に答える 1

1

コンストラクターを使用していてMat(int _rows, int _cols, int _type, void* _data, size_t _step=AUTO_STEP)、AUTO_STEPが0であり、行ストライドがであると想定していwidth*bytesPerPixelます。

これは一般的に間違っています—行をより大きな境界に揃えることは非常に一般的です。この場合、360は16の倍数ではありませんが、368は16の倍数です。これは、16ピクセルの境界に整列していることを強く示唆しています(おそらく、16×16ブロックで処理するアルゴリズムを支援するためですか?)。

試す

cv::Mat mat(videoRect.size.height, videoRect.size.width, CV_8UC4, baseaddress, CVPixelBufferGetBytesPerRow(pixelBuffer));
于 2013-03-07T02:33:57.940 に答える