BradLarson / GPUImage2

GPUImage 2 is a BSD-licensed Swift framework for GPU-accelerated video and image processing.
BSD 3-Clause "New" or "Revised" License
4.87k stars 609 forks source link

Capturing a photo from camera to uiimage ? #217

Closed jwoodrow closed 6 years ago

jwoodrow commented 6 years ago

Hi, I have a photo/gif app I made previously using AVFoundation as a base for the camera and taking photos, but I wanted to upgrade it to add some live filtering and post capture filtering too.

After some digging I found gpuimage/gpuimage2 and since my project is in swift 3 I started replacing my previous camera module with gpuimage.

I got the camera to work again but I have issues capturing a photo from the camera to store it as a uiimage until it is uploaded to a server.

do {
  self.videoCamera = try Camera(sessionPreset: AVCaptureSessionPresetPhoto, location: .frontFacing)
} catch {
  self.videoCamera = nil
  print("Couldn't initialize camera with error: \(error)")
}

this is my init and then this is where I place the camera feed in the view

self.filterView!.frame = self.view.frame
self.filterView!.orientation = .portraitUpsideDown
self.filterView!.fillMode = .preserveAspectRatioAndFill
self.videoCamera! --> self.filterView!
self.videoCamera!.startCapture()

as you can see for the moment I don't want to use any filters, I'm trying to first get the basic functionality back (i.e. showing a camera feed the taking 1-5 images in a row)

I noticed there was a saveNextFrameToURL but it saves the file on the device but I only want the uiimage so this is what I put to replace the content of my takePhoto method (images is nil on first run)

func takePhoto(){
  if self.images == nil {
    self.images = []
  }
  let pictureOutput = PictureOutput()
  pictureOutput.encodedImageFormat = .jpeg
  pictureOutput.imageAvailableCallback = {image in
    self.images!.append(image)
  }
  self.videoCamera! --> pictureOutput
}

My issue is that imageAvailableCallback is simply never called (I tried placing a breakpoint in it but nothing) whereas it goes through the rest of the method not raising any errors or warning.

what am I doing wrong ? is it even possible to capture a still image from a non filtered view ? if so how can I add a filter that would not change the image as such so I can still do some unedited photo capture in my app?

I've been going at it for over 2 weeks now and every time I search if anyone had the same issue I only find issues about editing a still image or a filtered image and when I tried filtering the image as such:

self.filterView!.frame = self.view.frame
self.filterView!.orientation = .portraitUpsideDown
self.filterView!.fillMode = .preserveAspectRatioAndFill
self.baseFilter = BrightnessAdjustment()
self.videoCamera! --> self.baseFilter --> self.filterView!
self.videoCamera!.startCapture()
func takePhoto(){
  if self.images == nil {
    self.images = []
  }
  let pictureOutput = PictureOutput()
  pictureOutput.encodedImageFormat = .jpeg
  pictureOutput.imageAvailableCallback = {image in
    self.images!.append(image)
  }
  self.baseFilter! --> pictureOutput
}

I get a white screen instead of my camera feed and still no image.

Any help would be appreciated thank you

jwoodrow commented 6 years ago

@BradLarson I know this is maybe as daft question, but I am really stuck on how to take a picture using gpuimage the imageAvailableCallback method is never called and I don't see anything else in the readme, examples and issues that show a working block of code to take a photo.

jwoodrow commented 6 years ago

Found my problem, the lifespan of my pictureOutput variable was too short so the callback was never done

Topwiz commented 6 years ago

@jwoodrow I'm having the same problem. The Callback isn't called. What do you meen the pictureoutput was too short? Can you give me some example capturing image and saving it?

jwoodrow commented 6 years ago

Hmm, well I'm not sure this would be your problem too but basically it was like this.

I had a class with a method to take pictures written as such

class SomeClass {
...
func takePhoto(){
  if self.images == nil {
    self.images = []
  }
  let pictureOutput = PictureOutput()
  pictureOutput.encodedImageFormat = .jpeg
  pictureOutput.imageAvailableCallback = {image in
    self.images!.append(image)
  }
  self.baseFilter! --> pictureOutput
}
...
}

became:

class SomeClass {
...
private weak var pictureOutput: PictureOutput!
...
func takePhoto(){
  if self.images == nil {
    self.images = []
  }
  self.pictureOutput = PictureOutput()
  self.pictureOutput.encodedImageFormat = .jpeg
  self.pictureOutput.imageAvailableCallback = {image in
    self.images!.append(image)
  }
  self.baseFilter! --> pictureOutput
}
...
}

So in my case my PictureOutput needed to outlast my function since the callback is asynchronous.

Topwiz commented 6 years ago

@jwoodrow Thank you that helped me. I got the image and saved it to the library. But I have an other question.. I saved it but the image size was 7501000, I'm using the sessionPreset to .Photo I want the size of 30244034. Can I do that with GPUImage2?

jwoodrow commented 6 years ago

@Topwiz I'm not entirely sure per say. But from my last experience trying to use GPUImage2 with an iPad pro you can't do those ultra high resolutions, I had to fall back to no live filtering (didn't want to bother with CIFilters at the time) and instead use AVFoundation purely (which isn't too complicated to setup, loads of guides and tutorials out there) and then once I got my picture I would pass it to GPUImage2 for the post filtering (so I would still get GPUImage2 performance for that part)