Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift 4: Get RGB values of pixel in UIImage

I know there have been lots of posts for how to get the colour of a pixel in a UIImage given a CGPoint but they are all outdated as far as I can tell. Most of them contain CGImageGetDataProvider and CGDataProviderCopyData which in Swift 4 is an error:

'CGImageGetDataProvider' has been replaced by property 'CGImage.dataProvider' 'CGDataProviderCopyData' has been replaced by property 'CGDataProvider.data'

Xcode suggests these substitutes, but they do not exist so I have been having trouble trying to recreate a Swift 4 function to get the colour of a pixel in a UIImage.

Here is the typical Swift 3 function:

extension UIImage {

    subscript (x: Int, y: Int) -> UIColor? {

        if x < 0 || x > Int(size.width) || y < 0 || y > Int(size.height) {
            return nil
        }

        let provider = CGImageGetDataProvider(self.cgImage!)
        let providerData = CGDataProviderCopyData(provider!)
        let data = CFDataGetBytePtr(providerData)

        let numberOfComponents = 4
        let pixelData = ((Int(size.width) * y) + x) * numberOfComponents

        let r = CGFloat(data![pixelData]) / 255.0
        let g = CGFloat(data![pixelData + 1]) / 255.0
        let b = CGFloat(data![pixelData + 2]) / 255.0
        let a = CGFloat(data![pixelData + 3]) / 255.0

        return UIColor(red: r, green: g, blue: b, alpha: a)
    }

}

Any suggestions or comments are greatly appreciated. Thank you!


EDIT

I tried @Mukesh 's solution but even though all the build errors are fixed, the program crashes. It says:

The image I give to the function is not nil, I have checked.


P.S. The image I am using for the function is a snapshot of the camera. I have a live camera and after every frame, this function (below) is called where I turn the current frame into a UIImage. This UIImage is what I want to find the pixel colour of:

func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
        let pixelBuffer: CVPixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)!
        let ciImg = CIImage(cvPixelBuffer: pixelBuffer)
        let cameraImage = UIImage(ciImage: ciImg)
        let col = cameraImage.getPixelColor(pos: CGPoint(x: 100, y: 100))
   }

I used CGPoint(x: 100, y: 100) to see if it crashed as an example, and it did. This point is also in the image because if it wasn't, it would have returned nil here:

if x < 0 || x > Int(size.width) || y < 0 || y > Int(size.height) {
            return nil
}

Is there a way to find out why it gets a nil value? Or maybe a different solution? Thank you :)

like image 232
J.Treutlein Avatar asked May 31 '18 12:05

J.Treutlein


People also ask

How to color hexadecimal numbers in Swift?

But often such sites will often use the hexadecimal system to describe the color. Swift fortunately can represent integers as hex values. Take the first two digits of the hex number as red, the next two as green, and the last two as blue. Write them with 0x prefixed to the number Red for #fde8d7 would be 0xfd for example.

Are red green and blue the same type in Swift?

These are not the same type, Swift is very cranky about type so we need to convert red, green and blue with a CGFloat initializer before we do anything else. Next, we checks which segment the user selected.

Can I access the underlying image data of an image object?

Thanks in advance! Because image objects are immutable, they also do not provide direct access to their underlying image data. However, you can get an functions.

What does sRGB mean in Swift?

For example, sRGB is a particular set of intensities for red, green and blue and defines the colors that can be reproduced by mixing those ranges of red, green and blue. How to work with UIColor objects using RGBA and HSBA values in Swift?


1 Answers

Here is the code I get after removing the errors:

extension UIImage {

    subscript (x: Int, y: Int) -> UIColor? {

        if x < 0 || x > Int(size.width) || y < 0 || y > Int(size.height) {
            return nil
        }

        let provider = self.cgImage!.dataProvider
        let providerData = provider!.data
        let data = CFDataGetBytePtr(providerData)

        let numberOfComponents = 4
        let pixelData = ((Int(size.width) * y) + x) * numberOfComponents

        let r = CGFloat(data![pixelData]) / 255.0
        let g = CGFloat(data![pixelData + 1]) / 255.0
        let b = CGFloat(data![pixelData + 2]) / 255.0
        let a = CGFloat(data![pixelData + 3]) / 255.0

        return UIColor(red: r, green: g, blue: b, alpha: a)
    }
}
like image 62
Mukesh Avatar answered Oct 27 '22 02:10

Mukesh