質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.99%

UIImageにCIFilterをかけたimageのタップ座標から、そのpixelの色を取得したい。

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 2,100

初めて質問させていただきます。

xcode内にリソースとして保存した画像を呼び出しimageViewとしてself.viewに配置します。 
配置したimageViewにtapGestureでタップイベントを追加させます。タップしたimageViewの座標から、そのpointの色を取ろうとしています。 

//インスタンス変数 
    var myImageView = UIImageView()

//xcode内に用意した.jpgファイルをimageViewとして表示。同時にimageViewにtapGestureを付与しました。
    override func viewDidLoad() {
        super.viewDidLoad()

        let image = UIImage(named: "testImage.jpg") 
        myImageView.image = image 

        myImageView.frame.origin = CGPointMake(0, 0) 
        myImageView.frame.size = image!.size 

        myImageView.userInteractionEnabled = true
        myImageView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: "tapAction:")) 

        self.view.addSubview(myImageView)
    }

//imageViewのタップ時にタップした座標のRGB値を表示する
    func tapAction(sender:UITapGestureRecognizer){ 
//タップした座標の取得 
        let tapPoint = sender.locationInView(self.myImageView)
//imageをdata化
        let pixelData = CGDataProviderCopyData(CGImageGetDataProvider(myImageView.image!.CGImage))
        let data: UnsafePointer = CFDataGetBytePtr(pixelData)

//タップした位置の座標にあたるアドレスを算出 
        let pixelAd: Int = ((Int(myImageView.image!.size.width) * Int(tapPoint.y)) + Int(tapPoint.x)) * 4

//それぞれRGBAの値をとる 
        let r = CGFloat(Int( CGFloat(data[pixelAd])/CGFloat(255.0)*100)) / 100 
        let g = CGFloat(Int( CGFloat(data[pixelAd+1])/CGFloat(255.0)*100)) / 100 
        let b = CGFloat(Int( CGFloat(data[pixelAd+2])/CGFloat(255.0)*100)) / 100 
        let a = CGFloat(Int( CGFloat(data[pixelAd+3])/CGFloat(255.0)*100)) / 100 

        let pixelColors = [r,g,b,a] 
        print(pixelColors) 
    }


上記のコードを実行すれば、たしかに指定の位置のRGBA値を出すことができます。 
しかしimageにfilterをかけて同じことをしようとしても、うまくいきません。 

//モノクロのフィルターを指定 
        let myFilter = CIFilter(name: "CIColorMonochrome")
        myFilter!.setValue(CIImage(image: myImageView.image!), forKey: kCIInputImageKey)
 //値の調整.
        myFilter!.setValue(CIColor(red: 0.5, green: 0.5, blue: 0.5), forKey: kCIInputColorKey)
        myFilter!.setValue(1.0, forKey: kCIInputIntensityKey)
 // フィルターを通した画像をアウトプット.
        let myOutputImage : CIImage = myFilter!.outputImage!
        let context = CIContext(options: nil)
        let cgImage = context.createCGImage(myOutputImage, fromRect: myOutputImage.extent)
        let newImage = UIImage(CGImage: cgImage)
 // 再びUIViewにセット.
        self.myImageView.image = newImage


このようにして上記と同様にtapActionを行っても、タップしたポイントとは異なるポイントのRGB値を表示します。 
フィルターをかけたimageのタップした座標の正しいRGB値の取り方をご教授いただければと思います。 

なお、UIImage(named: "testImage.jpg")のサイズは375*667です。 
別画像の1000*1000のサイズでは、フィルターをかけた場合でも、うまく指定の座標のrgb値を返しました。 
このようなこともあり混乱しています。 

どなたかお知恵を拝借できれば幸いです。 
長文失礼しました。

雑なコードで申し訳ございませんでした。修正しました。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • fuzzball

    2016/03/17 11:34

    場所によって変数名がマチマチで検証できませんので、まともなコードを載せて下さい。

    キャンセル

回答 1

checkベストアンサー

0

今回のケースは、画像の横サイズデータの横サイズが一致しないために起こっている現象だと思われます。(1000x1000のときは両者が一致しているので問題にならない)

//1ピクセルのバイト数
let bytesPerPixel = CGImageGetBitsPerPixel(myImageView.image!.CGImage) / 8
//1ラインのバイト数
let bytesPerRow = CGImageGetBytesPerRow(myImageView.image!.CGImage)
print("bytesPerPixel=\(bytesPerPixel) bytesPerRow=\(bytesPerRow)")

//タップした位置の座標にあたるアドレスを算出
let pixelAd: Int = Int(tapPoint.y) * bytesPerRow + Int(tapPoint.x) * bytesPerPixel

ついでに、1ピクセルのサイズもキチンと取得するようにしてみました。
375x667のときはフィルタの有無でbytesPerRowが違っているはずです。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/03/17 16:14

    早く正確な回答ありがとうございました。
    正しいやり方までご教授いただき本当に感謝いたします。

    どうしてもわからなかった部分がおかげさまでうまくいきました。
    重ねてになりますが、本当にありがとうございました!

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.99%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる