双指缩放相机
Pinch to zoom camera
我想捏一下来缩放相机,但我遇到了两个问题。首先是它允许用户放大太多和缩小太多,其次当我拍照时它不会拍摄放大的视图。这是我的捏功能代码...
func pinch(pinch: UIPinchGestureRecognizer) {
if let view = cameraView {
view.transform = CGAffineTransformScale(view.transform,
pinch.scale, pinch.scale)
pinch.scale = 1
}
}
如果您需要查看更多代码,请告诉我。谢谢!
我在相机实施方面遇到了同样的问题。要解决这个问题,您需要了解两件事。
- 最大和最小变焦必须在一个值内,否则会导致相机放大太多。
- 与实际图像不保存放大图像一样,这是一个常见的错误,很多在线解决方案都没有涵盖。这实际上是因为您只是更改了视图的缩放比例,而不是实际
AVCaptureDevice
的缩放比例。
要更改这两件事,您需要这样的东西:
func pinch(pinch: UIPinchGestureRecognizer) {
var device: AVCaptureDevice = self.videoDevice
var vZoomFactor = ((gestureRecognizer as! UIPinchGestureRecognizer).scale)
var error:NSError!
do{
try device.lockForConfiguration()
defer {device.unlockForConfiguration()}
if (vZoomFactor <= device.activeFormat.videoMaxZoomFactor){
device.videoZoomFactor = vZoomFactor
}else{
NSLog("Unable to set videoZoom: (max %f, asked %f)", device.activeFormat.videoMaxZoomFactor, vZoomFactor);
}
}catch error as NSError{
NSLog("Unable to set videoZoom: %@", error.localizedDescription);
}catch _{
}
}
如您所见,我为视频设备 (videoDevice
) 使用了一个 class 变量来跟踪我用于视觉组件的捕获设备。我将缩放限制在特定范围内并更改设备上的缩放 属性 而不是视图本身!
var device: AVCaptureDevice = self.backCamera
var vZoomFactor = sender.scale
var error:NSError!
do{
try device.lockForConfiguration()
defer {device.unlockForConfiguration()}
if (vZoomFactor <= device.activeFormat.videoMaxZoomFactor) {
let desiredZoomFactor:CGFloat = vZoomFactor + atan2(sender.velocity, 5.0);
device.videoZoomFactor = max(1.0, min(desiredZoomFactor, device.activeFormat.videoMaxZoomFactor));
}
else {
NSLog("Unable to set videoZoom: (max %f, asked %f)", device.activeFormat.videoMaxZoomFactor, vZoomFactor);
}
}
catch error as NSError{
NSLog("Unable to set videoZoom: %@", error.localizedDescription);
}
catch _{
}
如果需要手动zoomTo(2.0)功能,可以使用这个
// Create listener for Pinch to Zoom
let pinchRecognizer = UIPinchGestureRecognizer(target: self, action:#selector(FSCameraView.pinchToZoom(_:)))
pinchRecognizer.delegate = self
self.previewViewContainer.addGestureRecognizer(pinchRecognizer)
// set the zoom to a zoomed in mode from start
setZoom(CGFloat(2.0)
// and the functions
func pinchToZoom(sender:UIPinchGestureRecognizer) {
var vZoomFactor = ((sender as! UIPinchGestureRecognizer).scale)
setZoom(vZoomFactor)
}
func setZoom(zoomFactor:CGFloat) {
var device: AVCaptureDevice = self.device!
var error:NSError!
do{
try device.lockForConfiguration()
defer {device.unlockForConfiguration()}
if (zoomFactor <= device.activeFormat.videoMaxZoomFactor) {
let desiredZoomFactor:CGFloat = zoomFactor + atan2(sender.velocity, 5.0);
device.videoZoomFactor = max(1.0, min(desiredZoomFactor, device.activeFormat.videoMaxZoomFactor));
}
else {
NSLog("Unable to set videoZoom: (max %f, asked %f)", device.activeFormat.videoMaxZoomFactor, zoomFactor);
}
}
catch error as NSError{
NSLog("Unable to set videoZoom: %@", error.localizedDescription);
}
catch _{
}
}
要扩展 Ritvik Upadhyaya 的 答案,您还需要保存以前的缩放系数来计算新的缩放系数,您不希望缩放每次都重置为正常当您抬起手指并再次尝试缩放时。
// To track the zoom factor
var prevZoomFactor: CGFloat = 1
func pinch(pinch: UIPinchGestureRecognizer) {
var device: AVCaptureDevice = self.videoDevice
// Here we multiply vZoomFactor with the previous zoom factor if it exist.
// Else just multiply by 1
var vZoomFactor = pinch.scale * prevZoomFactor
// If the pinching has ended, update prevZoomFactor.
// Note that we set the limit at 1, because zoom factor cannot be less than 1 or the setting device.videoZoomFactor will crash
if sender.state == .ended {
prevZoomFactor = zoomFactor >= 1 ? zoomFactor : 1
}
do {
try device.lockForConfiguration()
defer {device.unlockForConfiguration()}
if (vZoomFactor <= device.activeFormat.videoMaxZoomFactor) {
device.videoZoomFactor = vZoomFactor
} else {
print("Unable to set videoZoom: (max \(device.activeFormat.videoMaxZoomFactor), asked \(vZoomFactor))")
}
} catch {
print("\(error.localizedDescription)")
}
}
Swift 3.0 || 4.0
1.定义缩放级别。
let minimumZoom: CGFloat = 1.0
let maximumZoom: CGFloat = 3.0
var lastZoomFactor: CGFloat = 1.0
2。在 CameraView 上添加捏合手势。
let pinchRecognizer = UIPinchGestureRecognizer(target: self, action:#selector(pinch(_:)))
self.viewCamera.addGestureRecognizer(pinchRecognizer)
3。具有zoomin
和zoom out
逻辑的捏动作方法
func pinch(_ pinch: UIPinchGestureRecognizer) {
guard let device = videoDeviceInput.device else { return }
// Return zoom value between the minimum and maximum zoom values
func minMaxZoom(_ factor: CGFloat) -> CGFloat {
return min(min(max(factor, minimumZoom), maximumZoom), device.activeFormat.videoMaxZoomFactor)
}
func update(scale factor: CGFloat) {
do {
try device.lockForConfiguration()
defer { device.unlockForConfiguration() }
device.videoZoomFactor = factor
} catch {
print("\(error.localizedDescription)")
}
}
let newScaleFactor = minMaxZoom(pinch.scale * lastZoomFactor)
switch pinch.state {
case .began: fallthrough
case .changed: update(scale: newScaleFactor)
case .ended:
lastZoomFactor = minMaxZoom(newScaleFactor)
update(scale: lastZoomFactor)
default: break
}
}
谢谢。快乐编码
您可以通过简单地将 UIPinchGestureRecognizer.scale
重置为 1 来避免保存 prevZoomFactor
,如下所示:
@IBAction func pinchAction(_ sender: UIPinchGestureRecognizer) {
guard let device = currentCaptureDevice else {return}
var zoom = device.videoZoomFactor * sender.scale
sender.scale = 1.0
var error:NSError!
do{
try device.lockForConfiguration()
defer {device.unlockForConfiguration()}
if zoom >= device.minAvailableVideoZoomFactor && zoom <= device.maxAvailableVideoZoomFactor {
device.videoZoomFactor = zoom
}else{
NSLog("Unable to set videoZoom: (max %f, asked %f)", device.activeFormat.videoMaxZoomFactor, zoom);
}
}catch error as NSError{
NSLog("Unable to set videoZoom: %@", error.localizedDescription);
}catch _{
}
}
这是 Apple 在我参加的一次 WWDC 活动中推荐的,当时手势识别器刚刚问世。
Swift 5.0 或以上
1.定义变量声明和出口。
//#MARK: - Outlets
@IBOutlet weak var camPreview: UIView!
let minimumZoom: CGFloat = 1.0
let maximumZoom: CGFloat = 2.0
var lastZoomFactor: CGFloat = 1.0
var newCamera: AVCaptureDevice?
2。在相机视图上获取相机位置和捏合手势。
//#MARK: - Views methods
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
newCamera = cameraWithPosition(position: .back)
//Add Pinch Gesture on CameraView.
let pinchRecognizer = UIPinchGestureRecognizer(target: self, action:#selector(pinch(_:)))
self.camPreview.addGestureRecognizer(pinchRecognizer)
}
// Find a camera with the specified AVCaptureDevicePosition, returning nil if one is not found
func cameraWithPosition(position: AVCaptureDevice.Position) -> AVCaptureDevice? {
let discoverySession = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: AVMediaType.video, position: .unspecified)
for device in discoverySession.devices {
if device.position == position {
return device
}
}
return nil
}
3。 Pinch-action 具有 zoom-in 和缩小功能。
@objc func pinch(_ pinch: UIPinchGestureRecognizer) {
guard let device = newCamera else { return }
// Return zoom value between the minimum and maximum zoom values
func minMaxZoom(_ factor: CGFloat) -> CGFloat {
return min(min(max(factor, minimumZoom), maximumZoom), device.activeFormat.videoMaxZoomFactor)
}
func update(scale factor: CGFloat) {
do {
try device.lockForConfiguration()
defer { device.unlockForConfiguration() }
device.videoZoomFactor = factor
} catch {
print("\(error.localizedDescription)")
}
}
let newScaleFactor = minMaxZoom(pinch.scale * lastZoomFactor)
switch pinch.state {
case .began: fallthrough
case .changed: update(scale: newScaleFactor)
case .ended:
lastZoomFactor = minMaxZoom(newScaleFactor)
update(scale: lastZoomFactor)
default: break
}
}
}
我想捏一下来缩放相机,但我遇到了两个问题。首先是它允许用户放大太多和缩小太多,其次当我拍照时它不会拍摄放大的视图。这是我的捏功能代码...
func pinch(pinch: UIPinchGestureRecognizer) {
if let view = cameraView {
view.transform = CGAffineTransformScale(view.transform,
pinch.scale, pinch.scale)
pinch.scale = 1
}
}
如果您需要查看更多代码,请告诉我。谢谢!
我在相机实施方面遇到了同样的问题。要解决这个问题,您需要了解两件事。
- 最大和最小变焦必须在一个值内,否则会导致相机放大太多。
- 与实际图像不保存放大图像一样,这是一个常见的错误,很多在线解决方案都没有涵盖。这实际上是因为您只是更改了视图的缩放比例,而不是实际
AVCaptureDevice
的缩放比例。
要更改这两件事,您需要这样的东西:
func pinch(pinch: UIPinchGestureRecognizer) {
var device: AVCaptureDevice = self.videoDevice
var vZoomFactor = ((gestureRecognizer as! UIPinchGestureRecognizer).scale)
var error:NSError!
do{
try device.lockForConfiguration()
defer {device.unlockForConfiguration()}
if (vZoomFactor <= device.activeFormat.videoMaxZoomFactor){
device.videoZoomFactor = vZoomFactor
}else{
NSLog("Unable to set videoZoom: (max %f, asked %f)", device.activeFormat.videoMaxZoomFactor, vZoomFactor);
}
}catch error as NSError{
NSLog("Unable to set videoZoom: %@", error.localizedDescription);
}catch _{
}
}
如您所见,我为视频设备 (videoDevice
) 使用了一个 class 变量来跟踪我用于视觉组件的捕获设备。我将缩放限制在特定范围内并更改设备上的缩放 属性 而不是视图本身!
var device: AVCaptureDevice = self.backCamera
var vZoomFactor = sender.scale
var error:NSError!
do{
try device.lockForConfiguration()
defer {device.unlockForConfiguration()}
if (vZoomFactor <= device.activeFormat.videoMaxZoomFactor) {
let desiredZoomFactor:CGFloat = vZoomFactor + atan2(sender.velocity, 5.0);
device.videoZoomFactor = max(1.0, min(desiredZoomFactor, device.activeFormat.videoMaxZoomFactor));
}
else {
NSLog("Unable to set videoZoom: (max %f, asked %f)", device.activeFormat.videoMaxZoomFactor, vZoomFactor);
}
}
catch error as NSError{
NSLog("Unable to set videoZoom: %@", error.localizedDescription);
}
catch _{
}
如果需要手动zoomTo(2.0)功能,可以使用这个
// Create listener for Pinch to Zoom
let pinchRecognizer = UIPinchGestureRecognizer(target: self, action:#selector(FSCameraView.pinchToZoom(_:)))
pinchRecognizer.delegate = self
self.previewViewContainer.addGestureRecognizer(pinchRecognizer)
// set the zoom to a zoomed in mode from start
setZoom(CGFloat(2.0)
// and the functions
func pinchToZoom(sender:UIPinchGestureRecognizer) {
var vZoomFactor = ((sender as! UIPinchGestureRecognizer).scale)
setZoom(vZoomFactor)
}
func setZoom(zoomFactor:CGFloat) {
var device: AVCaptureDevice = self.device!
var error:NSError!
do{
try device.lockForConfiguration()
defer {device.unlockForConfiguration()}
if (zoomFactor <= device.activeFormat.videoMaxZoomFactor) {
let desiredZoomFactor:CGFloat = zoomFactor + atan2(sender.velocity, 5.0);
device.videoZoomFactor = max(1.0, min(desiredZoomFactor, device.activeFormat.videoMaxZoomFactor));
}
else {
NSLog("Unable to set videoZoom: (max %f, asked %f)", device.activeFormat.videoMaxZoomFactor, zoomFactor);
}
}
catch error as NSError{
NSLog("Unable to set videoZoom: %@", error.localizedDescription);
}
catch _{
}
}
要扩展 Ritvik Upadhyaya 的 答案,您还需要保存以前的缩放系数来计算新的缩放系数,您不希望缩放每次都重置为正常当您抬起手指并再次尝试缩放时。
// To track the zoom factor
var prevZoomFactor: CGFloat = 1
func pinch(pinch: UIPinchGestureRecognizer) {
var device: AVCaptureDevice = self.videoDevice
// Here we multiply vZoomFactor with the previous zoom factor if it exist.
// Else just multiply by 1
var vZoomFactor = pinch.scale * prevZoomFactor
// If the pinching has ended, update prevZoomFactor.
// Note that we set the limit at 1, because zoom factor cannot be less than 1 or the setting device.videoZoomFactor will crash
if sender.state == .ended {
prevZoomFactor = zoomFactor >= 1 ? zoomFactor : 1
}
do {
try device.lockForConfiguration()
defer {device.unlockForConfiguration()}
if (vZoomFactor <= device.activeFormat.videoMaxZoomFactor) {
device.videoZoomFactor = vZoomFactor
} else {
print("Unable to set videoZoom: (max \(device.activeFormat.videoMaxZoomFactor), asked \(vZoomFactor))")
}
} catch {
print("\(error.localizedDescription)")
}
}
Swift 3.0 || 4.0
1.定义缩放级别。
let minimumZoom: CGFloat = 1.0
let maximumZoom: CGFloat = 3.0
var lastZoomFactor: CGFloat = 1.0
2。在 CameraView 上添加捏合手势。
let pinchRecognizer = UIPinchGestureRecognizer(target: self, action:#selector(pinch(_:)))
self.viewCamera.addGestureRecognizer(pinchRecognizer)
3。具有zoomin
和zoom out
func pinch(_ pinch: UIPinchGestureRecognizer) {
guard let device = videoDeviceInput.device else { return }
// Return zoom value between the minimum and maximum zoom values
func minMaxZoom(_ factor: CGFloat) -> CGFloat {
return min(min(max(factor, minimumZoom), maximumZoom), device.activeFormat.videoMaxZoomFactor)
}
func update(scale factor: CGFloat) {
do {
try device.lockForConfiguration()
defer { device.unlockForConfiguration() }
device.videoZoomFactor = factor
} catch {
print("\(error.localizedDescription)")
}
}
let newScaleFactor = minMaxZoom(pinch.scale * lastZoomFactor)
switch pinch.state {
case .began: fallthrough
case .changed: update(scale: newScaleFactor)
case .ended:
lastZoomFactor = minMaxZoom(newScaleFactor)
update(scale: lastZoomFactor)
default: break
}
}
谢谢。快乐编码
您可以通过简单地将 UIPinchGestureRecognizer.scale
重置为 1 来避免保存 prevZoomFactor
,如下所示:
@IBAction func pinchAction(_ sender: UIPinchGestureRecognizer) {
guard let device = currentCaptureDevice else {return}
var zoom = device.videoZoomFactor * sender.scale
sender.scale = 1.0
var error:NSError!
do{
try device.lockForConfiguration()
defer {device.unlockForConfiguration()}
if zoom >= device.minAvailableVideoZoomFactor && zoom <= device.maxAvailableVideoZoomFactor {
device.videoZoomFactor = zoom
}else{
NSLog("Unable to set videoZoom: (max %f, asked %f)", device.activeFormat.videoMaxZoomFactor, zoom);
}
}catch error as NSError{
NSLog("Unable to set videoZoom: %@", error.localizedDescription);
}catch _{
}
}
这是 Apple 在我参加的一次 WWDC 活动中推荐的,当时手势识别器刚刚问世。
Swift 5.0 或以上
1.定义变量声明和出口。
//#MARK: - Outlets
@IBOutlet weak var camPreview: UIView!
let minimumZoom: CGFloat = 1.0
let maximumZoom: CGFloat = 2.0
var lastZoomFactor: CGFloat = 1.0
var newCamera: AVCaptureDevice?
2。在相机视图上获取相机位置和捏合手势。
//#MARK: - Views methods
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
newCamera = cameraWithPosition(position: .back)
//Add Pinch Gesture on CameraView.
let pinchRecognizer = UIPinchGestureRecognizer(target: self, action:#selector(pinch(_:)))
self.camPreview.addGestureRecognizer(pinchRecognizer)
}
// Find a camera with the specified AVCaptureDevicePosition, returning nil if one is not found
func cameraWithPosition(position: AVCaptureDevice.Position) -> AVCaptureDevice? {
let discoverySession = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: AVMediaType.video, position: .unspecified)
for device in discoverySession.devices {
if device.position == position {
return device
}
}
return nil
}
3。 Pinch-action 具有 zoom-in 和缩小功能。
@objc func pinch(_ pinch: UIPinchGestureRecognizer) {
guard let device = newCamera else { return }
// Return zoom value between the minimum and maximum zoom values
func minMaxZoom(_ factor: CGFloat) -> CGFloat {
return min(min(max(factor, minimumZoom), maximumZoom), device.activeFormat.videoMaxZoomFactor)
}
func update(scale factor: CGFloat) {
do {
try device.lockForConfiguration()
defer { device.unlockForConfiguration() }
device.videoZoomFactor = factor
} catch {
print("\(error.localizedDescription)")
}
}
let newScaleFactor = minMaxZoom(pinch.scale * lastZoomFactor)
switch pinch.state {
case .began: fallthrough
case .changed: update(scale: newScaleFactor)
case .ended:
lastZoomFactor = minMaxZoom(newScaleFactor)
update(scale: lastZoomFactor)
default: break
}
}
}