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

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

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

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Swift

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

Q&A

解決済

1回答

2766閲覧

CGImage.initから生成した画像をUIImage形式に変換し、UIImageViewに表示させようとするとThread 1: EXC_BAD_ACCESSエラーが出る。

naoharuiwai

総合スコア18

iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Swift

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

0グッド

0クリップ

投稿2018/09/25 11:40

前提・実現したいこと

Swift初心者です。
勉強のため、画像をカメラまたはフォトライブラリから取り込み、フーリエ変換するアプリを作ろうとしています。
アプリの流れとしては、
1.カメラまたはフォトライブラリから画像を取り込む。
2.画面遷移し、取り込んだ画像を白黒画像に変換したものを表示する。
3.「画像をフーリエ変換」ボタンを押すことで、表示されている画像に対してフーリエ変換が行われる。
4.フーリエ変換が終了すると同時に、画面遷移しフーリエ変換した後の画像を表示する。

上記4にて、Thread 1: EXC_BAD_ACCESSエラーが出てしまいました。
色々試した結果、どうやらCGImage.initにて生成した画像をUIImage形式に変換し、UIImageViewに表示させようとするとエラーが発生しているようです。
どなたか解決方法を教えて頂けないでしょうか。

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

Thread 1: EXC_BAD_ACCESS (code=1, address=0x10833c020) // addressの部分はビルドごとに変わります。

該当のソースコード

ConfirmViewController

1import UIKit 2 3class ConfirmViewController: UIViewController { 4 5 let dft = 1 // flag 6 let idft = -1 7 8 @IBOutlet weak var fourierButton: UIButton! 9 10 override func viewDidLoad() { 11 super.viewDidLoad() 12 13 // Do any additional setup after loading the view. 14 15 // 前画面から渡された画像をセット 16 confirmImage.image = originalImage 17 fourierButton.layer.cornerRadius = 10.0 18 19 } 20 21 /* 22 // MARK: - Navigation 23 24 // In a storyboard-based application, you will often want to do a little preparation before navigation 25 override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 26 // Get the new view controller using segue.destination. 27 // Pass the selected object to the new view controller. 28 } 29 */ 30 @IBOutlet weak var confirmImage: UIImageView! 31 32 // 前画面から渡された画像を格納するための変数 33 var originalImage: UIImage? 34 35 // 「画像をフーリエ変換」ボタンをタップした時の処理 36 var transformImage: UIImage? 37 @IBAction func fourierButtonAction(_ sender: Any) { 38 39 // 表示されている画像から輝度値を取得する 40 let imageData = getByteArrayFromImage(image: confirmImage.image!) 41 42 // 得られた輝度値を二次元離散フーリエ変換する 43 // 画像のwidth,heightを取得 44 let width = Int((confirmImage.image?.size.width)!) 45 let height = Int((confirmImage.image?.size.height)!) 46 print(width) 47 print(height) 48 // サンプル数 49 let length = imageData.count 50 // 実数部分と虚数部分を格納する配列 51 var re = [Double](repeating: 0, count: length) 52 var im = [Double](repeating: 0, count: length) 53 54 for i in 0..<length{ 55 re[i] = Double(imageData[i]) 56 im[i] = 0 57 } 58 59 // 転置 60 dft_swap2(re: &re, im: &im, width: width, height: height) 61 // 二次元離散フーリエ変換 62 dft_idft2(re: &re, im: &im, width: width, height: height, flag: dft) 63 // 得られた二次元配列をもとに画像を生成 64 let releaseData: CGDataProviderReleaseDataCallback = { (info: UnsafeMutableRawPointer?, data: UnsafeRawPointer, size: Int) -> () in 65 print("callback") 66 return 67 } 68 let provider = CGDataProvider.init(dataInfo: nil, data: re, size: length, releaseData: releaseData) 69 let bitsPerComponent:Int = 8 70 let bitsPerPixel:Int = bitsPerComponent // グレースケールなので 71 let bytesperRow:Int = width 72 let colorSpaceRef = CGColorSpaceCreateDeviceGray() 73 let bitmapInfo = CGBitmapInfo.byteOrderMask 74 let renderingIntent = CGColorRenderingIntent.defaultIntent 75 if let cgImage = CGImage.init(width: width, height: height, bitsPerComponent: bitsPerComponent, bitsPerPixel: bitsPerPixel, bytesPerRow: bytesperRow, space: colorSpaceRef, bitmapInfo: bitmapInfo, provider: provider!, decode: nil, shouldInterpolate: false, intent: renderingIntent) { 76 transformImage = UIImage(cgImage: cgImage) 77 } 78 79 self.performSegue(withIdentifier: "goAfterFourierTransform", sender: nil) 80 } 81 //画面遷移時に画像を渡す 82 override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 83 if let afterViewController = segue.destination as? AfterFourierTransformViewController{ 84 //次の画面のインスタンスに取得した画像を渡す 85 afterViewController.nextOriginalImage = transformImage 86 } 87 } 88 89 90 // 輝度値を取得する関数 91 func getByteArrayFromImage(image: UIImage) -> [Int] { 92 // まずUIImage形式の画像をCGImage形式に変換する。 93 let imageRef = image.cgImage 94 // CGImageのプロバイダー 95 let imageProvider = imageRef?.dataProvider 96 let imageData = imageProvider?.data 97 let length = CFDataGetLength(imageData) 98 // RGBA輝度値を最初に格納する配列 99 var rawData = [UInt8](repeating: 0, count: length) 100 CFDataGetBytes(imageData, CFRange(location: 0, length: length), &rawData) 101 // 得たRGBA輝度値をグレースケールに変換 102 var gray = [Int](repeating: 0, count: length/4) 103 for i in 0..<length/4 { 104 gray[i] = Int(0.299*Double(rawData[4*i]) + 0.587*Double(rawData[4*i + 1]) + 0.114*Double(rawData[4*i + 2])) 105 } 106 107 return gray 108 } 109 110 /////////////////////////////////////////////////////////////////////////////////// 111 /////////////////////////////////////////////////////////////////////////////////// 112 /////////////////////////////////////////////////////////////////////////////////// 113 114 115 //二次元配列の転置 116 func dft_swap2(re:inout [Double], im:inout [Double], width:Int, height:Int){ 117 var temp:Double = 0.0 118 for i in 0..<height/2{ 119 for j in 0..<width/2{ 120 temp = re[width*i + j] 121 re[width*i + j] = re[width*(height/2+i) + width/2 + j] 122 re[width*(height/2+i) + width/2 + j] = temp 123 124 temp = im[width*i + j] 125 im[width*i + j] = im[width*(height/2+i) + width/2 + j] 126 im[width*(height/2+i) + width/2 + j] = temp 127 128 temp = re[width*i + width/2 + j] 129 re[width*i + width/2 + j] = re[width*(height/2+i) + j] 130 re[width*(height/2+i) + j] = temp 131 132 temp = im[width*i + width/2 + j] 133 im[width*i + width/2 + j] = im[width*(height/2+i) + j] 134 im[width*(height/2+i) + j] = temp 135 } 136 } 137 } 138 139 // 一次元配列の離散フーリエ変換 140 func dft_idft(re: inout [Double], im: inout [Double], num: Int, flag: Int){ 141 var temp_re = [Double](repeating: 0.0, count: num) 142 var temp_im = [Double](repeating: 0.0, count: num) 143 var coefficient: Double = 0.0 144 145 if(flag == idft){ 146 coefficient = Double(num) 147 } else { 148 coefficient = 1.0 149 } 150 151 for i in 0..<num { 152 for j in 0..<num { 153 temp_re[i] += re[j]*cos(2.0*Double.pi*Double(i)*Double(j)/Double(num)) + Double(flag)*im[j]*sin(2.0*Double.pi*Double(i)*Double(j)/Double(num)) 154 temp_im[i] += im[j]*cos(2.0*Double.pi*Double(i)*Double(j)/Double(num)) - Double(flag)*re[j]*sin(2.0*Double.pi*Double(i)*Double(j)/Double(num)) 155 } 156 temp_re[i] /= coefficient 157 temp_im[i] /= coefficient 158 } 159 160 for i in 0..<num { 161 re[i] = temp_re[i] 162 im[i] = temp_im[i] 163 } 164 } 165 166 167 168 // 二次元配列の離散フーリエ変換 169 func dft_idft2(re: inout [Double], im: inout [Double], width: Int, height: Int, flag: Int){ 170 var temp_re = [Double](repeating: 0.0, count: width*height) 171 var temp_im = [Double](repeating: 0.0, count: width*height) 172 173 // 二次元配列を一行ずつ横方向に離散フーリエ変換していく 174 for i in 0..<height { 175 for j in 0..<width { 176 temp_re[j] = re[i*width + j] 177 temp_im[j] = im[i*width + j] 178 } 179 180 dft_idft(re: &temp_re, im: &temp_im, num: width, flag: flag) 181 182 183 for j in 0..<width { 184 re[i*width + j] = temp_re[j] 185 im[i*width + j] = temp_im[j] 186 } 187 } 188 189 // 次は一列ずつ縦方向に離散フーリエ変換していく 190 for j in 0..<width { 191 for i in 0..<height { 192 temp_re[i] = re[i*width + j] 193 temp_im[i] = im[i*width + j] 194 } 195 196 dft_idft(re: &temp_re, im: &temp_im, num: height, flag: flag) 197 198 for i in 0..<height { 199 re[i*width + j] = temp_re[i] 200 im[i*width + j] = temp_im[i] 201 } 202 } 203 // 最終的にre[i]とim[i]が二次元離散フーリエ変換されたのちの配列となる 204 } 205}

AfterFourierTransformViewController

1 2import UIKit 3 4class AfterFourierTransformViewController: UIViewController { 5 6 @IBOutlet weak var fourierImage: UIImageView! 7 8 9 override func viewDidLoad() { 10 super.viewDidLoad() 11 12 // Do any additional setup after loading the view. 13 14 fourierImage.image = nextOriginalImage 15 } 16 17 18 var nextOriginalImage: UIImage? 19 20 /* 21 // MARK: - Navigation 22 23 // In a storyboard-based application, you will often want to do a little preparation before navigation 24 override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 25 // Get the new view controller using segue.destination. 26 // Pass the selected object to the new view controller. 27 } 28 */ 29}

試したこと

AfterFourierTransformViewController

1fourierImage.image = nextOriginalImage

の部分をコメントアウトすると画面遷移されましたので、この部分でエラーが起きているようです。


ConfirmViewControllerにて、試しに画面遷移をする前に、同じ画面上にフーリエ変換後の画像を表示させてみようとしました。

ConfirmViewController

1@IBOutlet weak var afterImage: UIImageView! // フーリエ変換後の画像を表示するImageView

を追加し、フーリエ変換したのちに

ConfirmViewController

1afterImage.image = transformImage

で画像を表示させようとしたところ、この部分でエラーが起きました。

以上から考えるに、どうやら二次元配列から生成した画像をUIImageViewに表示させようとするとエラーが発生するようですが、その解決方法が分かりません、、。

補足情報(FW/ツールのバージョンなど)

Swift4
Xcode10beta

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

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

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

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

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

guest

回答1

0

ベストアンサー

fourierImageやafterImageのアウトレットが繋がっていないのでは?

投稿2018/09/26 00:57

fuzzball

総合スコア16731

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

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

naoharuiwai

2018/09/26 03:55

Connection Inspectorで確認してみましたが、どちらもアウトレットは繋がっていました。 すみません、書き忘れましたが、上記のafterImageのアウトレットはstoryboardからコネクトして追加したものです。 再度UIImageViewから繋ぎ直してみましたが、それでも同じ段階でエラーを吐きました。
fuzzball

2018/09/26 04:00

「試し」の方で、print(afterImage)とprint(transformImage)の出力を教えて下さい。
naoharuiwai

2018/09/26 04:42

print(afterImage) Optional(<UIImageView: 0x10531abb0; frame = (59.5 320; 256 256); opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <CALayer: 0x2832ed8e0>>) print(transformImage) Optional(<UIImage: 0x2819ccd90> size {750, 1000} orientation 0 scale 1.000000) となりました。
fuzzball

2018/09/26 04:51

afterImage.image = UIImage() にするとどうなりますか?
fuzzball

2018/09/26 04:59

もう一つ、落ちたとき、他にメッセージは出てないですか?
naoharuiwai

2018/09/26 05:09

print(afterImage)の出力は、 Optional(<UIImageView: 0x103f3f600; frame = (59.5 320; 256 256); opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <CALayer: 0x2824f5160>>) となりました。 変わっていない気がします、、。
naoharuiwai

2018/09/26 05:11

見落としていました。 Debag Navigatorにて、 #0 0x00000001911bfce4 in ERROR_CGDataProvider_BufferIsNotReadable () が出ていました。 コンソールには、printの出力以外、何もメッセージが出ていないです。
fuzzball

2018/09/26 05:28

afterImage.image = UIImage() でも落ちるのでしょうか? それならば、この行で落ちているとは考えにくいです。 https://forums.developer.apple.com/thread/94163 同じ原因かどうか分かりませんが、ここを見るとiOS11.2辺りからの症状のようですね。 小さな画像でも落ちるでしょうか?
naoharuiwai

2018/09/26 06:04

はい。afterImage.image = UIImage()でも落ちます。 そうなんですね。ありがとうございます。 画像のサイズを128*128や64*64に変更して試してみましたが、どちらでも落ちました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.49%

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

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

質問する

関連した質問