Skip to content

Instantly share code, notes, and snippets.

@edom18
Created February 23, 2014 16:10
Show Gist options
  • Save edom18/9173315 to your computer and use it in GitHub Desktop.
Save edom18/9173315 to your computer and use it in GitHub Desktop.
[Objective-C] AVCaptureとvImageを使ってリアルタイムフィルタを作ってみる ref: http://qiita.com/edo_m18/items/727bee5affe6e36d77c2
#import <Accelerate/Accelerate.h>
#import <AVFoundation/AVFoundation.h>
self.captureSession = [[AVCaptureSession alloc] init];
gaussianblur(&inputvImage, &outputvImage);
// ビットマップコンテキストの生成
CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Little | kCGImageAlphaPremultipledFirst;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef cgContext = CGBitmapContextCreate(outputvImage.data, width, height, 8, bytesPerRow, colorSpace, bitmapInfo);
// 画像の作成
CGImageRef dstImage = CGBitmapContextCreateImage(cgContext);
__typeof(self) __weak wself = self;
dispatch_sync(dispatch_get_main_queue(), ^{
wself.previewLayer.contents = (__bredge id)dstImage;
});
// 解放処理
free(outBuffer);
CGImageRelease(dstImage);
CGContextReleaes(cgContext);
CGColorSpaceRelease(colorSpace);
// バッファのアンロック
CVPicelBufferUnlockBaseAddress(imageBufer, 0);
void gaussianblur(const vImage_Buffer *src, const vImage_Buffer *dst) {
const int16_t kernel[] = {
1, 4, 6, 4, 1,
4, 16, 24, 16, 4,
6, 24, 36, 24, 6,
4, 16, 24, 16, 4,
1, 4, 6, 4, 1
};
int length = sizeof(kernel) / sizeof(int16_t);
int32_t divisor = 0;
for (int i = 0; i < length; i++) {
divisor += kernel[i];
}
unsigned int size = sqrt(length);
uint32_t kernel_height = size;
uint32_t kernel_width = size;
vImageConvolve_ARGB8888(src, dst, NULL, 0, 0, kernel, kernel_height, kernel_width, divisor, NULL, kvImageCopyInPlace);
}
typedef short int16_t;
typedef int int32_t;
/* 8 bit planar pixel value */
typedef uint8_t Pixel_8;
typedef unsigned char uint8_t;
/* ARGB interleaved (8 bit/channel) pixel value. uint8_t[4] = { alpha, red, green, blue } */
typedef uint8_t Pixel_8888[4];
/* Pedantic: A number of pixels. For LP64 (ppc64/x86_64) this is a 64-bit quantity. */
typedef unsigned long vImagePixelCount;
typedef struct vImage_Buffer
{
void *data; /* Pointer to the top left pixel of the buffer. */
vImagePixelCount height; /* The height (in pixels) of the buffer */
vImagePixelCount width; /* The width (in pixels) of the buffer */
size_t rowBytes; /* The number of bytes in a pixel row, including any unused space between one row and the next. */
} vImage_Buffer;
/* Pedantic: A number of pixels. For LP64 (ppc64/x86_64) this is a 64-bit quantity. */
typedef unsigned long vImagePixelCount;
vImageConvolve_ARGB8888(
&src, // const vImage_Buffer *src
&dst, // const vImage_Buffer *dest
NULL, // void *tempBuffer
0, // vImagePixelCount srcOffsetToROI_X
0, // vImagePixelCount srcOffsetToROI_Y
kernelArray, // const int16_t *kernel
3, // uint32_t kernel_height
3, // uint32_t kernel_width
divisor, // int32_t divisor
NULL, // Pixel_8888 backgroundColor
kvImageCopyInPlace // vImage_Flags flags
);
<Error>: CGBitmapContextCreate: invalid data bytes/row: should be at least 1920 for 8 integer bits/component, 3 components, kCGImageAlphaPremultipliedFirst.
// 実際に使ってるやつ
const size_t bufferSize = CVPixelBufferGetDataSize(imageBuffer);
// 以下のように自前で計算してもOK
const size_t bufferSize = sizeof(uint8_t) * width * height * 4;
<Error>: CGBitmapContextCreate: invalid data bytes/row: should be at least 1920 for 8 integer bits/component, 3 components, kCGImageAlphaPremultipliedFirst.
// 実際に使ってるやつ
const size_t bufferSize = CVPixelBufferGetDataSize(imageBuffer);
// 以下のように自前で計算してもOK
const size_t bufferSize = sizeof(uint8_t) * width * height * 4;
NSArray *devices = [AVCaptureDevice devices];
AVCaptureDeviceInput *frontInput;
AVCaptureDeviceInput *backInput;
for (AVCaptureDevice *device in devices) {
if ([device hasMediaType:AVMediaTypeVideo]) {
NSError *error = nil;
if (device.position == AVCaptureDevicePositionFront) {
frontInput = [AVCaptureDeviceInput deviceInputWithDevice:device error:&error];
}
else {
backInput = [AVCaptureDeviceInput deviceInputWithDevice:device error:&error];
}
}
}
[self.captureSession addInput:backInput];
NSDictionary *settings;
settings = @{(NSString *)kCVPixelBufferPixelFormatTypeKey:@(kCVPixelFormatType_32BGRA)};
self.videoOutput = [[AVCaptureVideoDataOutput alloc] init];
[self.videoOutput setVideoSettings:settings];
[self.videoOutput setAlwaysDiscardsLateVideoFrame:YES];
[self.captureSession addOutput:self.videoOutput];
// カメラの向きを設定
AVCaptureConnection *videoConnection = nil;
[self.captureSession beginConfiguration];
for (AVCaptureConnection *connection in [self.videoOutput connections]) {
for (AVCaptureInputPort *port in [connection inputPorts]) {
if ([[port mediaType] isEqual:AVMediaTypeVideo]) {
videoConnection = connection;
}
}
}
if ([videoConnection isVideoOrientationSupported]) {
[videoConnection setVideoOrientation:AVCaptureVideoOrientationPortrait];
}
[self.captureSession commitConfiguration];
dispatch_queue_t queue = dispatch_queue_create("VideoQueue", DISPATCH_QUEUE_SERIAL);
[self.videoOutput setSampleBufferDelegate:self queue:queue];
self.previewLayer = [AVCaptureVideoPreviewLayer layer];
self.previewLayer.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
self.previewLayer.position = CGPointMake(self.view.frame.size.width / 2, self.view.frame.size.height / 2);
[self.view.layer addSublayer:self.previewLayer];
CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
CVPixelBufferLockBaseAddress(imageBuffer, 0);
size_t width = CVPixelBufferGetWidth(imageBuffer);
size_t height = CVPixelBufferGetHeight(imageBuffer);
size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer);
const size_t bufferSize = CVPixelBufferGetDataSize(imageBuffer);
// 入力用
uint_8 *buffer = (uint8_t *)CVPixelBufferGetBaseAddress(imageBuffer);
const vImage_Buffer inputvImage = {buffer, height, width, bytesPerRow};
// 出力用
void *outBuffer = malloc(bufferSize); // 出力用に空のメモリを確保
const vImage_Buffer outputvImage = {outBuffer, height, width, bytesPerRow};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment