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

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

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

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

Q&A

解決済

1回答

1082閲覧

swiftによる画像二値化アプリの開発

hiyorin

総合スコア2

Swift

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

0グッド

0クリップ

投稿2023/04/05 13:29

実現したいこと

swiftでの画像二値化アプリの開発

前提

swiftで画像二値化アプリの開発を行なっています。
現在、画像を読み込んで二値化することまではできているのですが、スライダーによる閾値の変化を行うことができていません。
開発、質問ともに初心者であるため、見にくい点などあると思いますがお力添えをいただけると幸いです。

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

スライダーを動かしても、二値化した画像が変化しない。

該当のソースコード

swift

1// 2// ContentView.swift 3// Image_Swift 4// 5// 6 7import SwiftUI 8import UIKit 9 10extension UIImage { 11 func createBinarizedImage(r:[CGFloat], g: [CGFloat], b:[CGFloat], a:[CGFloat], threshold:CGFloat) -> UIImage{ 12 UIGraphicsBeginImageContextWithOptions(size, false, 0) 13 let wid:Int = Int(size.width) 14 let hei:Int = Int(size.height) 15 for w in 0..<wid { 16 for h in 0..<hei { 17 let index = (w * wid) + h 18 var color = 0.2126 * r[index] + 0.7152 * g[index] + 0.0722 * b[index] 19 if color > threshold / 100 { 20 color = 255 21 } else { 22 color = 0 23 } 24 UIColor(red: color, green: color, blue: color, alpha: a[index]).setFill() 25 let drawRect = CGRect(x: w, y: h, width: 1, height: 1) 26 UIRectFill(drawRect) 27 draw(in: drawRect, blendMode: .destinationIn, alpha: 1) 28 } 29 } 30 let binarizeImage = UIGraphicsGetImageFromCurrentImageContext()! 31 UIGraphicsEndImageContext() 32 return binarizeImage 33 34 } 35} 36 37class ViewController: UIViewController { 38 @IBOutlet weak var image: UIImageView! 39 40 var r:[CGFloat] = [] 41 var g:[CGFloat] = [] 42 var b:[CGFloat] = [] 43 var a:[CGFloat] = [] 44 45 var threshold:CGFloat = 0.0 46 47 override func viewDidLoad() { 48 super.viewDidLoad() 49 let img = UIImage(named: "Lena")! 50 51 // ピクセルごとの色情報の取得、下記のPixelBufferクラスの関数を使用している。 52 if let pixelBuffer = PixelBuffer(uiImage: img) { 53 for x in 0..<pixelBuffer.width { 54 for y in 0..<pixelBuffer.height { 55 r.append(pixelBuffer.getRed(x: x, y: y)) 56 g.append(pixelBuffer.getBlue(x: x, y: y)) 57 b.append(pixelBuffer.getGreen(x: x, y: y)) 58 a.append(pixelBuffer.getAlpha(x: x, y: y)) 59 } 60 } 61 } else { 62 print("image not format") 63 } 64 65 image.image = img.createBinarizedImage(r: r, g: g, b: b, a: a, threshold: threshold) 66 67 } 68} 69 70class PixelBuffer { 71 private var pixelData: Data 72 var width: Int 73 var height: Int 74 private var bytesPerRow: Int 75 private let bytesPerPixel = 4 //1ピクセルが4バイトのデータしか扱わない 76 77 init?(uiImage: UIImage) { 78 guard let cgImage = uiImage.cgImage, 79 //R,G,B,A各8Bit 80 cgImage.bitsPerComponent == 8, 81 //1 pixelが32bit 82 cgImage.bitsPerPixel == bytesPerPixel * 8 else { 83 return nil 84 85 } 86 pixelData = cgImage.dataProvider!.data! as Data 87 width = cgImage.width 88 height = cgImage.height 89 bytesPerRow = cgImage.bytesPerRow 90 } 91 92 func getRed(x: Int, y: Int) -> CGFloat { 93 let pixelInfo = bytesPerRow * y + x * bytesPerPixel 94 let r = CGFloat(pixelData[pixelInfo]) / CGFloat(255.0) 95 96 return r 97 } 98 func getGreen(x: Int, y: Int) -> CGFloat { 99 let pixelInfo = bytesPerRow * y + x * bytesPerPixel 100 let green = CGFloat(pixelData[pixelInfo+1]) / CGFloat(255.0) 101 102 return green 103 } 104 func getBlue(x: Int, y: Int) -> CGFloat { 105 let pixelInfo = bytesPerRow * y + x * bytesPerPixel 106 let blue = CGFloat(pixelData[pixelInfo+2]) / CGFloat(255.0) 107 108 return blue 109 } 110 func getAlpha(x: Int, y: Int) -> CGFloat { 111 let pixelInfo = bytesPerRow * y + x * bytesPerPixel 112 let alpha = CGFloat(pixelData[pixelInfo+3]) / CGFloat(255.0) 113 return alpha 114 } 115} 116 117 118struct ContentView: View { 119 120 @State var bin = 50.0 121 122 @State var isEditing = false 123 124 @State var img = UIImage(named: "Lena") 125 @State var img_bin :UIImage? 126 127 128 init() { 129 if let pixelBuffer = PixelBuffer(uiImage: img!) { 130 var r = [CGFloat]() 131 var g = [CGFloat]() 132 var b = [CGFloat]() 133 var a = [CGFloat]() 134 for x in 0..<pixelBuffer.width { 135 for y in 0..<pixelBuffer.height { 136 r.append(pixelBuffer.getRed(x: x, y: y)) 137 g.append(pixelBuffer.getGreen(x: x, y: y)) 138 b.append(pixelBuffer.getBlue(x: x, y: y)) 139 a.append(pixelBuffer.getAlpha(x: x, y: y)) 140 } 141 } 142 _img_bin = State(initialValue: img!.createBinarizedImage(r: r, g: g, b: b, a: a, threshold:bin)) 143 } else { 144 print("image not format") 145 } 146 } 147 148 var body: some View { 149 150 VStack{ 151 Image(uiImage:img!) 152 if let unwrap_img_bin = img_bin { 153 Image(uiImage:unwrap_img_bin) 154 } 155 else{ 156 Text("アンラップ失敗") 157 } 158 Slider( 159 value: $bin, 160 in: 0...100, 161 step: 1.0, 162 onEditingChanged: { 163 editing in 164 isEditing = editing 165 } 166 ) 167 168 Text("\(bin, specifier: "%.0f")") 169 .foregroundColor(isEditing ? .red : .blue) 170 171 } 172 } 173} 174 175 176struct ContentView_Previews: PreviewProvider { 177 static var previews: some View { 178 ContentView() 179 } 180} 181

試したこと

Lena以外の画像として、下記サイト様の"harumi"とLenaにアルファチャンネルを追加した画像は試してみましたが、同様の状況でした。

補足情報

こちらのサイト様を参考にさせていただいてます。
http://harumi.sakura.ne.jp/wordpress/2019/05/31/%E3%82%B0%E3%83%AC%E3%83%BC%E3%82%B9%E3%82%B1%E3%83%BC%E3%83%AB%E5%A4%89%E6%8F%9B/

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

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

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

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

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

guest

回答1

0

ベストアンサー

パフォーマンス的な改善の余地はあるのかもしれませんが、
スライダーに合わせて反映するとしたら、
次のような感じになるかなと思いました。
// ---のコメントを見てみてください。

swift

1import SwiftUI 2import UIKit 3 4extension UIImage { 5 func createBinarizedImage(r:[CGFloat], g: [CGFloat], b:[CGFloat], a:[CGFloat], threshold:CGFloat) -> UIImage{ 6 UIGraphicsBeginImageContextWithOptions(size, false, 0) 7 let wid:Int = Int(size.width) 8 let hei:Int = Int(size.height) 9 for w in 0..<wid { 10 for h in 0..<hei { 11 let index = (w * wid) + h 12 var color = 0.2126 * r[index] + 0.7152 * g[index] + 0.0722 * b[index] 13 if color > threshold / 100 { 14 color = 255 15 } else { 16 color = 0 17 } 18 UIColor(red: color, green: color, blue: color, alpha: a[index]).setFill() 19 let drawRect = CGRect(x: w, y: h, width: 1, height: 1) 20 UIRectFill(drawRect) 21 draw(in: drawRect, blendMode: .destinationIn, alpha: 1) 22 } 23 } 24 let binarizeImage = UIGraphicsGetImageFromCurrentImageContext()! 25 UIGraphicsEndImageContext() 26 return binarizeImage 27 } 28} 29 30class ViewController: UIViewController { 31 @IBOutlet weak var image: UIImageView! 32 var r:[CGFloat] = [] 33 var g:[CGFloat] = [] 34 var b:[CGFloat] = [] 35 var a:[CGFloat] = [] 36 var threshold:CGFloat = 0.0 37 override func viewDidLoad() { 38 super.viewDidLoad() 39 let img = UIImage(named: "Lena")! 40 // ピクセルごとの色情報の取得、下記のPixelBufferクラスの関数を使用している。 41 if let pixelBuffer = PixelBuffer(uiImage: img) { 42 for x in 0..<pixelBuffer.width { 43 for y in 0..<pixelBuffer.height { 44 r.append(pixelBuffer.getRed(x: x, y: y)) 45 g.append(pixelBuffer.getBlue(x: x, y: y)) 46 b.append(pixelBuffer.getGreen(x: x, y: y)) 47 a.append(pixelBuffer.getAlpha(x: x, y: y)) 48 } 49 } 50 } else { 51 print("image not format") 52 } 53 image.image = img.createBinarizedImage(r: r, g: g, b: b, a: a, threshold: threshold) 54 } 55} 56 57class PixelBuffer { 58 private var pixelData: Data 59 var width: Int 60 var height: Int 61 private var bytesPerRow: Int 62 private let bytesPerPixel = 4 //1ピクセルが4バイトのデータしか扱わない 63 init?(uiImage: UIImage) { 64 guard let cgImage = uiImage.cgImage, 65 //R,G,B,A各8Bit 66 cgImage.bitsPerComponent == 8, 67 //1 pixelが32bit 68 cgImage.bitsPerPixel == bytesPerPixel * 8 else { 69 return nil 70 } 71 pixelData = cgImage.dataProvider!.data! as Data 72 width = cgImage.width 73 height = cgImage.height 74 bytesPerRow = cgImage.bytesPerRow 75 } 76 77 func getRed(x: Int, y: Int) -> CGFloat { 78 let pixelInfo = bytesPerRow * y + x * bytesPerPixel 79 let r = CGFloat(pixelData[pixelInfo]) / CGFloat(255.0) 80 81 return r 82 } 83 func getGreen(x: Int, y: Int) -> CGFloat { 84 let pixelInfo = bytesPerRow * y + x * bytesPerPixel 85 let green = CGFloat(pixelData[pixelInfo+1]) / CGFloat(255.0) 86 87 return green 88 } 89 func getBlue(x: Int, y: Int) -> CGFloat { 90 let pixelInfo = bytesPerRow * y + x * bytesPerPixel 91 let blue = CGFloat(pixelData[pixelInfo+2]) / CGFloat(255.0) 92 93 return blue 94 } 95 func getAlpha(x: Int, y: Int) -> CGFloat { 96 let pixelInfo = bytesPerRow * y + x * bytesPerPixel 97 let alpha = CGFloat(pixelData[pixelInfo+3]) / CGFloat(255.0) 98 return alpha 99 } 100} 101 102struct ContentView: View { 103 @State var bin = 50.0 104 @State var isEditing = false 105 @State var img = UIImage(named: "th-917401218") 106 @State var img_bin :UIImage? 107 init() { 108 if let pixelBuffer = PixelBuffer(uiImage: img!) { 109 var r = [CGFloat]() 110 var g = [CGFloat]() 111 var b = [CGFloat]() 112 var a = [CGFloat]() 113 for x in 0..<pixelBuffer.width { 114 for y in 0..<pixelBuffer.height { 115 r.append(pixelBuffer.getRed(x: x, y: y)) 116 g.append(pixelBuffer.getGreen(x: x, y: y)) 117 b.append(pixelBuffer.getBlue(x: x, y: y)) 118 a.append(pixelBuffer.getAlpha(x: x, y: y)) 119 } 120 } 121 _img_bin = State(initialValue: img!.createBinarizedImage(r: r, g: g, b: b, a: a, threshold:bin)) 122 } else { 123 print("image not format") 124 } 125 } 126 // --- img_binを設定し直しすためのメソッドです。 127 func setimgbin() { 128 if let pixelBuffer = PixelBuffer(uiImage: img!) { 129 var r = [CGFloat]() 130 var g = [CGFloat]() 131 var b = [CGFloat]() 132 var a = [CGFloat]() 133 for x in 0..<pixelBuffer.width { 134 for y in 0..<pixelBuffer.height { 135 r.append(pixelBuffer.getRed(x: x, y: y)) 136 g.append(pixelBuffer.getGreen(x: x, y: y)) 137 b.append(pixelBuffer.getBlue(x: x, y: y)) 138 a.append(pixelBuffer.getAlpha(x: x, y: y)) 139 } 140 } 141 // --- createBinarizedImageが遅いためスライダーが滑らかになりません・・ 142 self.img_bin = img!.createBinarizedImage(r: r, g: g, b: b, a: a, threshold:bin) 143 } else { 144 print("image not format") 145 } 146 } 147 var body: some View { 148 VStack{ 149 Image(uiImage:img!) 150 if let unwrap_img_bin = img_bin { 151 Image(uiImage:unwrap_img_bin) 152 } 153 else{ 154 Text("アンラップ失敗") 155 } 156 Slider( 157 value: $bin, 158 in: 0...100, 159 step: 1.0, 160 onEditingChanged: { 161 editing in 162 isEditing = editing 163 // --- img_binを設定し直します。 164 setimgbin() 165 } 166 ) 167 Text("\(bin, specifier: "%.0f")") 168 .foregroundColor(isEditing ? .red : .blue) 169 } 170 } 171} 172 173struct ContentView_Previews: PreviewProvider { 174 static var previews: some View { 175 ContentView() 176 } 177}

投稿2023/04/05 13:50

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問