画像のヒストグラムを作る(1) (カラー画像編)

#画像のヒストグラムを作る

Swift5での画像のヒストグラムを作成する良いサンプルが無かったので覚書

公式サンプルに参考になるプロジェクトあり

https://developer.apple.com/documentation/accelerate/specifying_histograms_with_vimage


Accelerate.vImageのvImageHistogramCalculation_ARGB8888を利用して計算するよう
https://developer.apple.com/documentation/accelerate/1545743-vimagehistogramcalculation_argb8

この方法では，カラーチャネルが1chでは計算できないが，ひとまず目的は達成したので良しとする

```swift
import Accelerate.vImage

    func histogramCalculation(imageRef: CGImage) -> (red: [UInt], green: [UInt], blue: [UInt], alpha:[UInt])
    {
       
        let imgProvider: CGDataProvider = imageRef.dataProvider!
        let imgBitmapData: CFData = imgProvider.data!
        
        var imgBuffer = vImage_Buffer(
            data: UnsafeMutableRawPointer(mutating: CFDataGetBytePtr(imgBitmapData)),
            height: vImagePixelCount(imageRef.height),
            width: vImagePixelCount(imageRef.width),
            rowBytes: imageRef.bytesPerRow)
        
        
        // bins: zero = red, green = one, blue = two, alpha = three
        var histogramBinZero = [vImagePixelCount](repeating: 0, count: 256)
        var histogramBinOne = [vImagePixelCount](repeating: 0, count: 256)
        var histogramBinTwo = [vImagePixelCount](repeating: 0, count: 256)
        var histogramBinThree = [vImagePixelCount](repeating: 0, count: 256)

        histogramBinZero.withUnsafeMutableBufferPointer { zeroPtr in
            histogramBinOne.withUnsafeMutableBufferPointer { onePtr in
                histogramBinTwo.withUnsafeMutableBufferPointer { twoPtr in
                    histogramBinThree.withUnsafeMutableBufferPointer { threePtr in
                        
                        var histogramBins = [zeroPtr.baseAddress, onePtr.baseAddress,
                                             twoPtr.baseAddress, threePtr.baseAddress]
                        
                        histogramBins.withUnsafeMutableBufferPointer { histogramBinsPtr in
                            let error =  vImageHistogramCalculation_ARGB8888(&imgBuffer,
                                                                            histogramBinsPtr.baseAddress!,
                                                                            vImage_Flags(kvImageNoFlags))
                            
                            guard error == kvImageNoError else {
                                fatalError("Error calculating histogram: \(error)")
                            }
                        }
                    }
                }
            }
        }
        
        
        return (histogramBinZero, histogramBinOne, histogramBinTwo, histogramBinThree)
    }
```

iOSであれば，UIImageからcgImage作成は用意だが，macではNSImageなのでひと作業必要

```swift
var imageRect = NSRect(x: 0, y: 0, width: img.size.width, height: img.size.height)
guard let cgImg1 =  img.cgImage(forProposedRect: &imageRect, context: nil, hints: nil) else {
      abort()
}
```

##結果
![スクリーンショット 2021-05-10 0.30.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1465632/ece175e3-c115-2acc-7bb4-f8ebf5d864cd.png)
4000x3000の画像で試すと

```
 *func: load img, Time: 29.488ms
 *func: make cgImg 1, Time: 0.069ms
 *func: calc, Time: 162.501ms
 *func: make 3ch chart, Time: 0.109ms
 *func: draw, Time: 0.9739ms
```

十分な速度が出た
グラフはnsbezierPath curveを使うとなめらかになりそうだが
control point算出がめんどくさく，今回は直線でつないでいる

上記プロジェクトはGithubにおいておきます

https://github.com/STrizzle-Naoki/imageHistogram



ではまた