Core Image: merge two CIImage Swift - ios

So I have 2 CIImage that I want to merge together, so each with an alpha of 0.5. How can I do it?
I tired the following code but the resulting image is not the correct size and the two images aren't allied correctly... Please help!
if let image = CIImage(contentsOf: imageURL) {
let randomFilter = CIFilter(name: "CIRandomGenerator")
let noiseImage = randomFilter!.outputImage!.cropped(to: (CGRect(x: CGFloat(Int.random(in: 1..<1000)), y: CGFloat(Int.random(in: 1..<1000)), width: image.extent.width, height: image.extent.height)))
let compoimg = noiseImage.composited(over: image) //Misaligned image
}

The Problem lies on the random noise generator, because of it's nature that the random noise is cropped from an infinite noise map... the correct code compensates this translation:
if let image = CIImage(contentsOf: imageURL) {
let randomFilter = CIFilter(name: "CIRandomGenerator")
let randX = CGFloat(Int.random(in: 0..<1000))
let randY = CGFloat(Int.random(in: 0..<1000))
let noiseImage = randomFilter!.outputImage!.cropped(to: (CGRect(x: randX, y: randY, width: image.extent.width, height: image.extent.height)))
let tt = noiseImage.transformed(by: CGAffineTransform.init(translationX: -randX, y: -randY))
let compoimg = tt.composited(over: image) //Correctly allied image
}

Related

How do I get the distance of a specific coordinate from the screen size depthMap of ARDepthData?

I am trying to get the distance of a specific coordinate from a depthMap resized to the screen size, but it is not working.
I have tried to implement the following steps.
convert the depthMap to CIImage, and then resize the image to the orientation and size of the screen using affine transformation
convert the converted image to a screen-sized CVPixelBuffer
get the distance in meters stored in CVPixelBuffer from a one-dimensional array by width * y + x when getting the coordinates of (x, y).
I have implemented the above procedure, but I cannot get the appropriate index from the one-dimensional array. What should I do?
The code for the procedure is shown below.
1.
let depthMap = depthData.depthMap
// convert the depthMap to CIImage
let image = CIImage(cvPixelBuffer: depthMap)
let imageSize = CGSize(width: depthMap.width, height: depthMap.height)
// 1) キャプチャ画像を 0.0〜1.0 の座標に変換
let normalizeTransform = CGAffineTransform(scaleX: 1.0/imageSize.width, y: 1.0/imageSize.height)
// 2) 「Flip the Y axis (for some mysterious reason this is only necessary in portrait mode)」とのことでポートレートの場合に座標変換。
// Y軸だけでなくX軸も反転が必要。
let interfaceOrientation = self.arView.window!.windowScene!.interfaceOrientation
let flipTransform = (interfaceOrientation.isPortrait) ? CGAffineTransform(scaleX: -1, y: -1).translatedBy(x: -1, y: -1) : .identity
// 3) キャプチャ画像上でのスクリーンの向き・位置に移動
let displayTransform = frame.displayTransform(for: interfaceOrientation, viewportSize: arView.bounds.size)
// 4) 0.0〜1.0 の座標系からスクリーンの座標系に変換
let toViewPortTransform = CGAffineTransform(scaleX: arView.bounds.size.width, y: arView.bounds.size.height)
// 5) 1〜4までの変換を行い、変換後の画像をスクリーンサイズでクリップ
let transformedImage = image.transformed(by: normalizeTransform.concatenating(flipTransform).concatenating(displayTransform).concatenating(toViewPortTransform)).cropped(to: arView.bounds)
// convert the converted image to a screen-sized CVPixelBuffer
if let convertDepthMap = transformedImage.pixelBuffer(cgSize: arView.bounds.size) {
previewImage.image = transformedImage.toUIImage()
DispatchQueue.main.async {
self.processDepthData(convertDepthMap)
}
}
// The process of acquiring CVPixelBuffer is implemented in extension
extension CIImage {
func toUIImage() -> UIImage {
UIImage(ciImage: self)
}
func pixelBuffer(cgSize size:CGSize) -> CVPixelBuffer? {
var pixelBuffer: CVPixelBuffer?
let attrs = [kCVPixelBufferCGImageCompatibilityKey: kCFBooleanTrue,
kCVPixelBufferCGBitmapContextCompatibilityKey: kCFBooleanTrue] as CFDictionary
let width:Int = Int(size.width)
let height:Int = Int(size.height)
CVPixelBufferCreate(kCFAllocatorDefault,
width,
height,
kCVPixelFormatType_DepthFloat32,
attrs,
&pixelBuffer)
// put bytes into pixelBuffer
let context = CIContext()
context.render(self, to: pixelBuffer!)
return pixelBuffer
}
}
private func processDepthData(_ depthMap: CVPixelBuffer) {
CVPixelBufferLockBaseAddress(depthMap, .readOnly)
let width = CVPixelBufferGetWidth(depthMap)
let height = CVPixelBufferGetHeight(depthMap)
if let baseAddress = CVPixelBufferGetBaseAddress(depthMap) {
let mutablePointer = baseAddress.bindMemory(to: Float32.self, capacity: width*height)
let bufferPointer = UnsafeBufferPointer(start: mutablePointer, count: width*height)
let depthArray = Array(bufferPointer)
CVPixelBufferUnlockBaseAddress(depthMap, .readOnly)
// index = width * y + x to trying to get the distance in meters for the coordinate of (300, 100), but it gets the distance for another coordinate
print(depthArray[width * 100 + 300])
}
}

Why is my photo becoming bigger?, Swift, iOS

I am using the AVFoundation to take a photo but when I do the photo image that comes back is more enlarged than the photo I took.
Does anyone know why this would be?
I have the camera in landscape mode.
Below is my code for taking the image and then assigning it to a new variable.
var cropArea:CGRect{
get{
let factor = backImage.image!.size.width/view.frame.width
let scale = CGFloat(1)
let imageFrame = viewFinder.imageFrame()
let x = (cropAreaView.frame.origin.x - imageFrame.origin.x) * scale * factor
let y = (cropAreaView.frame.origin.y - imageFrame.origin.y) * scale * factor
let width = cropAreaView.frame.size.width * scale * factor
let height = cropAreaView.frame.size.height * scale * factor
return CGRect(x: x, y: y, width: width, height: height)
}
}
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
if let imageData = photo.fileDataRepresentation() {
print(imageData)
image = UIImage(data: imageData)
backImage.image = image
let croppedCGImage = self.backImage.image?.cgImage?.cropping(to: self.cropArea)
let croppedImage = UIImage(cgImage: croppedCGImage!)
self.pictureView.image = croppedImage

Trying to make the kCIInputCenterKey for image filters based on touch location and The y coordinate is flipped

I would appreciate some help on converting my X and Y touch coordinates to proper CIVectors. The code below is everything I'm using to have a "touch" be the kCIInputCenterKey coordinate for the bump distortion. It works somewhat but the Y coordinate is flipped when i touch the screen to apply the choose a center key for the filter. X is correct but if i touch on the top of the image the filter is applied on the opposite lower part of the image while retaining correct x axis location
var xCord:CGFloat = 0.0
var yCord:CGFloat = 0.0
func didTapImage(gesture: UIGestureRecognizer) {
let point = gesture.location(in: gesture.view)
print(point)
xCord = point.x
yCord = point.y
print ("\(point) and x\(xCord) and \(yCord)")
}
#IBAction func filter(_ sender: Any) {
guard let image = self.imageView.image?.cgImage else { return }
let openGLContext = EAGLContext(api: .openGLES3)
let context = CIContext(eaglContext: openGLContext!)
let ciImage = CIImage(cgImage: image)
let filter = CIFilter(name: "CIBumpDistortion")
filter?.setValue(ciImage, forKey: kCIInputImageKey)
filter?.setValue((CIVector(x: xCord, y: yCord)), forKey: kCIInputCenterKey)
filter?.setValue(300.0, forKey: kCIInputRadiusKey)
filter?.setValue(2.50, forKey: kCIInputScaleKey)
centerScrollViewContents()
if let output = filter?.value(forKey: kCIOutputImageKey) as? CIImage{
self.imageView.image = UIImage(cgImage: context.createCGImage(output, from: output.extent)!)
}
}
The problem is the yCord is flipped for some reason coming from being a float to a Vector. When I try to correct this by using something like:
filter?.setValue((CIVector(x: xCord, y: -yCord)), forKey: kCIInputCenterKey)
or
filter?.setValue((CIVector(x: xCord, y: yCord * (-1))), forKey: kCIInputCenterKey)
It causes the entire image to jump up or down in the image view and the filter doesn't get applied to it anywhere. Not sure where to go from here since the value doesn't want to be flipped with simple math.
Any help would be greatly appreciated!
I found the solution.
to flip the y correctly all I had to do was:
filter?.setValue((CIVector(x: xCord, y: CGFloat(image.height) - yCord)), forKey: kCIInputCenterKey)

Swift 3 - How do I improve image quality for Tesseract?

I am using Swift 3 to build a mobile app that allows the user to take a picture and run Tesseract OCR over the resulting image.
However, I've been trying to increase the quality of scan and it doesn't seem to be working much. I've segmented the photo into a more "zoomed in" region that I want to recognize and even tried making it black and white. Are there any strategies for "enhancing" or optimizing the picture quality/size so that Tesseract can recognize it better? Thanks!
tesseract.image = // the camera photo here
tesseract.recognize()
print(tesseract.recognizedText)
I got these errors and have no idea what to do:
Error in pixCreateHeader: depth must be {1, 2, 4, 8, 16, 24, 32}
Error in pixCreateNoInit: pixd not made
Error in pixCreate: pixd not made
Error in pixGetData: pix not defined
Error in pixGetWpl: pix not defined
2017-03-11 22:22:30.019717 ProjectName[34247:8754102] Cannot convert image to Pix with bpp = 64
Error in pixSetYRes: pix not defined
Error in pixGetDimensions: pix not defined
Error in pixGetColormap: pix not defined
Error in pixClone: pixs not defined
Error in pixGetDepth: pix not defined
Error in pixGetWpl: pix not defined
Error in pixGetYRes: pix not defined
Please call SetImage before attempting recognition.Please call SetImage before attempting recognition.2017-03-11 22:22:30.026605 EOB-Reader[34247:8754102] No recognized text. Check that -[Tesseract setImage:] is passed an image bigger than 0x0.
ive been using tesseract fairly successfully in swift 3 using the following:
func performImageRecognition(_ image: UIImage) {
let tesseract = G8Tesseract(language: "eng")
var textFromImage: String?
tesseract?.engineMode = .tesseractCubeCombined
tesseract?.pageSegmentationMode = .singleBlock
tesseract?.image = imageView.image
tesseract?.recognize()
textFromImage = tesseract?.recognizedText
print(textFromImage!)
}
I also found pre-processing the image helped too. I added the following extension to UIImage
import UIKit
import CoreImage
extension UIImage {
func toGrayScale() -> UIImage {
let greyImage = UIImageView()
greyImage.image = self
let context = CIContext(options: nil)
let currentFilter = CIFilter(name: "CIPhotoEffectNoir")
currentFilter!.setValue(CIImage(image: greyImage.image!), forKey: kCIInputImageKey)
let output = currentFilter!.outputImage
let cgimg = context.createCGImage(output!,from: output!.extent)
let processedImage = UIImage(cgImage: cgimg!)
greyImage.image = processedImage
return greyImage.image!
}
func binarise() -> UIImage {
let glContext = EAGLContext(api: .openGLES2)!
let ciContext = CIContext(eaglContext: glContext, options: [kCIContextOutputColorSpace : NSNull()])
let filter = CIFilter(name: "CIPhotoEffectMono")
filter!.setValue(CIImage(image: self), forKey: "inputImage")
let outputImage = filter!.outputImage
let cgimg = ciContext.createCGImage(outputImage!, from: (outputImage?.extent)!)
return UIImage(cgImage: cgimg!)
}
func scaleImage() -> UIImage {
let maxDimension: CGFloat = 640
var scaledSize = CGSize(width: maxDimension, height: maxDimension)
var scaleFactor: CGFloat
if self.size.width > self.size.height {
scaleFactor = self.size.height / self.size.width
scaledSize.width = maxDimension
scaledSize.height = scaledSize.width * scaleFactor
} else {
scaleFactor = self.size.width / self.size.height
scaledSize.height = maxDimension
scaledSize.width = scaledSize.height * scaleFactor
}
UIGraphicsBeginImageContext(scaledSize)
self.draw(in: CGRect(x: 0, y: 0, width: scaledSize.width, height: scaledSize.height))
let scaledImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return scaledImage!
}
func orientate(img: UIImage) -> UIImage {
if (img.imageOrientation == UIImageOrientation.up) {
return img;
}
UIGraphicsBeginImageContextWithOptions(img.size, false, img.scale)
let rect = CGRect(x: 0, y: 0, width: img.size.width, height: img.size.height)
img.draw(in: rect)
let normalizedImage : UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return normalizedImage
}
}
And then called this before passing the image to performImageRecognition
func processImage() {
self.imageView.image! = self.imageView.image!.toGrayScale()
self.imageView.image! = self.imageView.image!.binarise()
self.imageView.image! = self.imageView.image!.scaleImage()
}
Hope this helps

Select portion of the uiimage with given color

I would like to implement a feature that allows user to select a given color from the image and replace it with transparent color. Ideally it would work similar to Pixelmator, https://www.youtube.com/watch?v=taXGaQC0JBg where user can select colors and see which portions of the image are currently selected and a slider that can be used to select the tolerance of the colors.
My primary suspect for the replacing colors is CGImageCreateWithMaskingColors() function. Perhaps CIColorCube might do the job.
I am not sure how to proceed with visualizing the selection of the colors. Any tips will be welcome!
thank you,
Janusz
EDIT:
I am moving very slowly but I made some progress. I am using imageCreateWithMaskingColors function to extract unwanted colors:
func imageWithMaskingColors(){
//get uiimage
let image:CGImageRef = self.inputImage.image!.CGImage
let maskingColors :[CGFloat] = [0,200,0,255,0,255]
let newciimage = CGImageCreateWithMaskingColors(image,maskingColors)
let newImage = UIImage(CGImage: newciimage)
self.outputImage.image = newImage
let w = CGFloat(CGImageGetWidth(newciimage))
let h = CGFloat(CGImageGetHeight(newciimage))
let size = CGSizeMake(w,h)
UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
let context = UIGraphicsGetCurrentContext();
newImage?.drawInRect(CGRectMake(0, 0, w, h))
let result = UIGraphicsGetImageFromCurrentImageContext();
self.inputImage1 = result.CGImage
UIGraphicsEndImageContext();
}
In the next step I am applying a CISourceOutCompositing CIFilter to get a selected area, that was removed in last step:
#IBAction func blendMode(){
let context = CIContext(options: nil)
let inputImage:CIImage = CIImage(CGImage:self.inputImage1)
var filter = CIFilter(name: "CISourceOutCompositing")
println(inputImage.debugDescription)
//mix it with black
let fileURL = NSBundle.mainBundle().URLForResource("black", withExtension: "jpg")
var backgroundImage = CIImage(contentsOfURL: fileURL)
filter.setValue(inputImage, forKey: kCIInputBackgroundImageKey)
filter.setValue(backgroundImage, forKey: kCIInputImageKey)
println(backgroundImage.debugDescription)
let outputImage = filter.outputImage
println(outputImage.debugDescription)
let cgimg = context.createCGImage(outputImage, fromRect: outputImage.extent())
blendImage1 = cgimg
let newImage = UIImage(CGImage: cgimg)
self.outputImage.image = newImage
}
In the next step I would like to add a dashed-stroke line to borders and remove the filling color of the selected image (black tiger).
I used a GPUImage CannyEdgeDetectionFilter to the image but it didn't give me satysfiying results (black image)
let gpaPicture = GPUImagePicture(CGImage: blendImage1)
let canny = GPUImageCannyEdgeDetectionFilter()
//canny.upperThreshold = CGFloat(1125)
canny.lowerThreshold = CGFloat(1)
gpaPicture.addTarget(canny)
canny.useNextFrameForImageCapture()
gpaPicture.processImage()
let gpuResult = canny.imageByFilteringImage(UIImage(CGImage:blendImage1))

Resources