У меня есть простой AVCaptureSession, который работает, чтобы получить канал камеры в моем приложении и делать фотографии. Как я могу реализовать функциональность «щепотка для увеличения», используя UIGestureRecognizer
для камеры?AVCaptureDevice Camera Zoom
ответ
Принятый ответ на самом деле устарел, и я не уверен, что он фактически сделает снимок увеличенного изображения. Существует метод увеличения масштаба, например, ответ на битков. Проблема его ответа заключается в том, что он не берет на себя ответственность за то, что пользователь может увеличить масштаб, а затем возобновить работу с этой позиции масштабирования. Его решение создаст какие-то прыжки, которые не очень элегантны.
Самый простой и элегантный способ сделать это - использовать скорость жестов щепотка.
-(void) handlePinchToZoomRecognizer:(UIPinchGestureRecognizer*)pinchRecognizer {
const CGFloat pinchVelocityDividerFactor = 5.0f;
if (pinchRecognizer.state == UIGestureRecognizerStateChanged) {
NSError *error = nil;
if ([videoDevice lockForConfiguration:&error]) {
CGFloat desiredZoomFactor = device.videoZoomFactor + atan2f(pinchRecognizer.velocity, pinchVelocityDividerFactor);
// Check if desiredZoomFactor fits required range from 1.0 to activeFormat.videoMaxZoomFactor
device.videoZoomFactor = MAX(1.0, MIN(desiredZoomFactor, device.activeFormat.videoMaxZoomFactor));
[videoDevice unlockForConfiguration];
} else {
NSLog(@"error: %@", error);
}
}
}
Я обнаружил, что добавление функции arctan в скорость облегчит масштабирование эффекта уменьшения. Это не совсем идеально, но эффект достаточно хорош для потребностей. Там, вероятно, может быть другая функция, чтобы облегчить масштаб, когда он почти достигает 1.
ПРИМЕЧАНИЕ: Кроме того, масштаб пинч жест идет от 0 до бесконечности с 0 до 1 существо зажимая в (уменьшение) и 1 до бесконечного сжатия (увеличение). Чтобы получить хороший эффект уменьшения масштаба, вам нужно будет иметь математическое уравнение. Скорость - от -инфините до бесконечности, а 0 - исходная.
EDIT: Исправлена ошибка при превышении допустимого диапазона. Благодаря @garafajon!
Спасибо. Используйте это, чтобы не получить исключение диапазона: \t \t \t CGFloat wishZoom = videoDevice.videoZoomFactor + atan (pinchRecognizer.velocity/pinchZoomScaleFactor); \t \t \t videoDevice.videoZoomFactor = MAX (1.0, MIN (желательноZoom, видеоDevice.activeFormat.videoMaxZoomFactor)); – garafajon
замечательный! Оно работает. – Sourabh
Помните, что скорость может возвращать nan. Возможно, вы захотите проверить это, прежде чем переходить к вычислению: if (isnan (pinchRecognizer.velocity)) {return; } – Masa
Многие попытались сделать это, установив свойство преобразования на слой на CGAffineTransformMakeScale(gesture.scale.x, gesture.scale.y);
См. here для полноценной реализации масштабирования.
Спасибо за ответ. Но как просто изменение масштаба просмотра видеоизображения фактически меняет масштаб аппаратного обеспечения камеры? –
Это не так. Вот почему даже камера Apple по-настоящему не масштабируется. Это всего лишь некоторые CGAffines, и некоторые причудливые кадрирования. – CodaFi
Правильно, камера просто использует «цифровой зум». Но что еще я должен делать за пределами масштабирования вида предварительного просмотра видео, чтобы на самом деле сделать изображение записываемым на диск «увеличенным»? –
С iOS 7 вы можете установить масштаб напрямую с помощью свойства videoZoomFactor
AVCaptureDevice
.
Свяжите scale
имущество UIPinchGestureRecognizer
с videoZoomFactor
с константой масштабирования. Это позволит вам варьировать чувствительность к вкусу:
-(void) handlePinchToZoomRecognizer:(UIPinchGestureRecognizer*)pinchRecognizer {
const CGFloat pinchZoomScaleFactor = 2.0;
if (pinchRecognizer.state == UIGestureRecognizerStateChanged) {
NSError *error = nil;
if ([videoDevice lockForConfiguration:&error]) {
videoDevice.videoZoomFactor = 1.0 + pinchRecognizer.scale * pinchZoomScaleFactor;
[videoDevice unlockForConfiguration];
} else {
NSLog(@"error: %@", error);
}
}
}
Обратите внимание, что AVCaptureDevice
, а все остальное связано с AVCaptureSession
, не поточно. Поэтому вы, вероятно, не хотите делать это из основной очереди.
Я использую IOS SDK 8.3 и рамки AVfoundation и для меня, используя следующий метод работал:
nameOfAVCaptureVideoPreviewLayer.affineTransform = CGAffineTransformMakeScale(scaleX, scaleY)
Для сохранения картины с той же шкале, я использовал следующий метод:
nameOfAVCaptureConnection.videoScaleAndCropFactor = factorNumber;
код ниже для получения изображения в масштабе
[stillImageOutput captureStillImageAsynchronouslyFromConnection:videoConnnection completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {
if(imageDataSampleBuffer != NULL){
NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
UIImage *image = [UIImage imageWithData:imageData];
}
}];
в SWIF t, вы можете увеличивать/уменьшать масштаб, просто передавая масштабированный номер на videoZoomFactor. Следующий код в обработчике UIPinchGestureRecognizer решит проблему.
do {
try device.lockForConfiguration()
switch gesture.state {
case .began:
self.pivotPinchScale = device.videoZoomFactor
case .changed:
var factor = self.pivotPinchScale * gesture.scale
factor = max(1, min(factor, device.activeFormat.videoMaxZoomFactor))
device.videoZoomFactor = factor
default:
break
}
device.unlockForConfiguration()
} catch {
// handle exception
}
Здесь pivotPinchScale - это свойство CGFloat, которое где-то указано в вашем контроллере.
Вы также можете обратиться к следующему проекту, чтобы узнать, как работает камера с UIPinchGestureRecognizer. https://github.com/DragonCherry/CameraPreviewController
Swift 4
Добавить щепотку жест распознаватель на вид спереди, наиболее и подключить его к этому действию (pinchToZoom). captureDevice должен быть экземпляром, предоставляющим входные данные для сеанса захвата. pinchToZoom обеспечивает плавное масштабирование как для спереди & назад улавливающие устройства.
@IBAction func pinchToZoom(_ sender: UIPinchGestureRecognizer) {
guard let device = captureDevice else { return }
func minMaxZoom(_ factor: CGFloat) -> CGFloat { return min(max(factor, 1.0), device.activeFormat.videoMaxZoomFactor) }
func update(scale factor: CGFloat) {
do {
try device.lockForConfiguration()
defer { device.unlockForConfiguration() }
device.videoZoomFactor = factor
} catch {
debugPrint(error)
}
}
let newScaleFactor = minMaxZoom(pinch.scale * zoomFactor)
switch sender.state {
case .began: fallthrough
case .changed: update(scale: newScaleFactor)
case .ended:
zoomFactor = minMaxZoom(newScaleFactor)
update(scale: zoomFactor)
default: break
}
}
Будет полезно объявить zoomFactor на вашей камере или в. Обычно я помещаю его в один синглтон с AVCaptureSession. Это будет действовать в качестве значения по умолчанию для videoZoomFactor.
var zoomFactor: Float = 1.0
Куда вы добавляете пинч-жест? – Dalvik