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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

解決済

1回答

973閲覧

画像二値化アプリの開発

hiyorin

総合スコア2

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

0クリップ

投稿2023/03/30 08:56

編集2023/04/01 06:31

ヘディングのテキスト### 実現したいこと

swiftを用いたiOS向け画像二値化アプリの開発

前提

swiftでiOS向け画像二値化アプリの開発をおこなっています。
下のサイト様を参考に開発を進めていたのですが、アンラップがうまくいきません。お力添えを頂けますと幸いです。ttp://harumi.sakura.ne.jp/wordpress/2019/06/03/%E4%BA%8C%E5%80%A4%E5%8C%96/

発生している問題・エラーメッセージ

下記のプログラム中の154行目else文、"アンラップ失敗"は本来望んでいない状況なのですが、こちらが表示されてしまいます。 150行目のif文に入るためにはどこを直すべきでしょうか?

// // ContentView.swift // Image_Swift // // import SwiftUI import UIKit extension UIImage { func createBinarizedImage(r:[CGFloat], g: [CGFloat], b:[CGFloat], a:[CGFloat], threshold:CGFloat) -> UIImage{ UIGraphicsBeginImageContextWithOptions(size, false, 0) let wid:Int = Int(size.width) let hei:Int = Int(size.height) //let threshold:CGFloat = 128/255 for w in 0..<wid { for h in 0..<hei { let index = (w * wid) + h var color = 0.2126 * r[index] + 0.7152 * g[index] + 0.0722 * b[index] if color > threshold { color = 255 } else { color = 0 } UIColor(red: color, green: color, blue: color, alpha: a[index]).setFill() let drawRect = CGRect(x: w, y: h, width: 1, height: 1) UIRectFill(drawRect) draw(in: drawRect, blendMode: .destinationIn, alpha: 1) } } let binarizeImage = UIGraphicsGetImageFromCurrentImageContext()! UIGraphicsEndImageContext() return binarizeImage } } class ViewController: UIViewController { @IBOutlet weak var image: UIImageView! var r:[CGFloat] = [] var g:[CGFloat] = [] var b:[CGFloat] = [] var a:[CGFloat] = [] var threshold:CGFloat = 0.0 override func viewDidLoad() { super.viewDidLoad() let img = UIImage(named: "Lena")! // ピクセルごとの色情報の取得、下記のPixelBufferクラスの関数を使用している。 if let pixelBuffer = PixelBuffer(uiImage: img) { for x in 0..<pixelBuffer.width { for y in 0..<pixelBuffer.height { r.append(pixelBuffer.getRed(x: x, y: y)) g.append(pixelBuffer.getBlue(x: x, y: y)) b.append(pixelBuffer.getGreen(x: x, y: y)) a.append(pixelBuffer.getAlpha(x: x, y: y)) } } } else { print("image not format") } image.image = img.createBinarizedImage(r: r, g: g, b: b, a: a, threshold: threshold) } } class PixelBuffer { private var pixelData: Data var width: Int var height: Int private var bytesPerRow: Int private let bytesPerPixel = 4 //1ピクセルが4バイトのデータしか扱わない init?(uiImage: UIImage) { guard let cgImage = uiImage.cgImage, //R,G,B,A各8Bit cgImage.bitsPerComponent == 8, //1 pixelが32bit cgImage.bitsPerPixel == bytesPerPixel * 8 else { return nil } pixelData = cgImage.dataProvider!.data! as Data width = cgImage.width height = cgImage.height bytesPerRow = cgImage.bytesPerRow } func getRed(x: Int, y: Int) -> CGFloat { let pixelInfo = bytesPerRow * y + x * bytesPerPixel let r = CGFloat(pixelData[pixelInfo]) / CGFloat(255.0) return r } func getGreen(x: Int, y: Int) -> CGFloat { let pixelInfo = bytesPerRow * y + x * bytesPerPixel let green = CGFloat(pixelData[pixelInfo+1]) / CGFloat(255.0) return green } func getBlue(x: Int, y: Int) -> CGFloat { let pixelInfo = bytesPerRow * y + x * bytesPerPixel let blue = CGFloat(pixelData[pixelInfo+2]) / CGFloat(255.0) return blue } func getAlpha(x: Int, y: Int) -> CGFloat { let pixelInfo = bytesPerRow * y + x * bytesPerPixel let alpha = CGFloat(pixelData[pixelInfo+3]) / CGFloat(255.0) return alpha } } struct ContentView: View { @State var bin = 50.0 @State var isEditing = false @State var img = UIImage(named: "Lena") @State var img_bin :UIImage? init() { if let pixelBuffer = PixelBuffer(uiImage: img!) { var r = [CGFloat]() var g = [CGFloat]() var b = [CGFloat]() var a = [CGFloat]() for x in 0..<pixelBuffer.width { for y in 0..<pixelBuffer.height { r.append(pixelBuffer.getRed(x: x, y: y)) g.append(pixelBuffer.getGreen(x: x, y: y)) b.append(pixelBuffer.getBlue(x: x, y: y)) a.append(pixelBuffer.getAlpha(x: x, y: y)) } } img_bin = img!.createBinarizedImage(r: r, g: g, b: b, a: a, threshold:bin) } else { print("image not format") } } var body: some View { VStack{ Image(uiImage:img!) if let unwrap_img_bin = img_bin { Image(uiImage:unwrap_img_bin) } else{ Text("アンラップ失敗")//こっちになってしまっている } Slider( value: $bin, in: 0...100, onEditingChanged: { editing in isEditing = editing } ) Text("\(bin)") .foregroundColor(isEditing ? .red : .blue) } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }

試したこと

Lena以外の画像もいくつか試してみましたが、状況は変わりませんでした。

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2023/04/01 06:51

(最初回答のコメントに書いてしまったのですが、修正依頼のコメントにさせていただきました) ご返信ありがとうございます。 ごめんなさい、見当違いのことを書いてしまったみたいですね。 nilのためアンラップした時のコードが動かないとのことですが、 `print("image not format")`のようなコードが 62行目と142行目にあると思います。 どちらかのメッセージがコンソールに出力されていると思うのですが、 どちらのメッセージが出力されているかもご記載いただけますでしょうか? それから、可能でしたら、Lenaの画像か、他のでも良いですので、 「私が調べたところでは問題ない」画像をどこかアップしていただけますでしょうか? ネット上にある既存の画像へのリンクでもOKです。
guest

回答1

0

ベストアンサー

140行目のimg_binが設定されていないため、
nilをアンラップできないのかなと思いました。

それの原因になるのは、
127行目の
if let pixelBuffer = PixelBuffer(uiImage: img!) {
ですが、
PixelBufferクラスのイニシャライザ(77行目)を見る必要があると思います。

78行目〜85行目でguard構文がありますが、
ここでnilになっているのではないかと思います。

Lenaという画像が、
R,G,B,A各8Bit
1 pixelが32bit
になっているかどうか、
確認してみると良いのかなと思いました。

追記

ごめんなさい。
PNGの画像で確認していたから8bitとか32bitのところで弾かれていたようでした。
JPEGの画像で確認したところその先に進みました。

次のようにするとimg_binのプロパティが設定できると思います。

swift

1// img_bin = img!.createBinarizedImage(r: r, g: g, b: b, a: a, threshold:bin) 2 _img_bin = State(initialValue: img!.createBinarizedImage(r: r, g: g, b: b, a: a, threshold:bin))

@Stateのプロパティラッパー型は、init(イニシャライザ)で初期値を設定するのに、
ちょっと特殊な書き方をするみたいです。

_img_bin のようにプロパティ名の先頭に「_」をつけます。
設定する値はState(initialValue: ~) のようにState構造体のイニシャライザを呼び出す形にします。

次のstackoverflowのQAを参考にしました。
https://stackoverflow.com/questions/58758370/how-could-i-initialize-the-state-variable-in-the-init-function-in-swiftui

追記2

コメントありがとうございます。

しかし、表示された画像が真っ黒になってしまっており、原因がわからない状況です。

ごめんなさい。
質問内容が「アンラップできること」だったので、
そこまで確認していませんでした・・

20行目のif color > threshold {につきまして、
colorは0.5のような感じなのに対し、
thresholdの方は50(%単位?)のような感じのため、
全部elseの方(color = 0)になっているように見えました。

if color > threshold / 100 {
のように変更してみたらいかがでしょうか?

*createBinarizedImageを呼び出す時に単位変更の計算をしておいても良いと思います

投稿2023/03/30 09:28

編集2023/04/04 02:33
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hiyorin

2023/04/01 06:29

回答ありがとうございます。 ご指摘いただきましたLenaの画像についてですが、私が調べたところでは問題ないようでした。 いくつか他の画像でも試してみましたが、状況は変わりませんでした。
退会済みユーザー

退会済みユーザー

2023/04/01 06:51 編集

ご返信ありがとうございます。 ごめんなさい、見当違いのことを書いてしまったみたいですね。
hiyorin

2023/04/04 01:17

ありがとうございます!! アンラップが成功し、画像が表示されるようになりました! しかし、表示された画像が真っ黒になってしまっており、原因がわからない状況です。
hiyorin

2023/04/05 09:50

ありがとうございます!!!無事に画像が表示されました!!丁寧なご回答ありがとうございました!! スライダーを動かしても閾値が変更されないという問題点が残っていますが、本題とそれてしまうため一旦ベストアンサーにさせていただきます!!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問