今週までの目標
- ビタペックスと粘膜部の境界面抽出を実装
活動内容
- 境界面の抽出に成功
- 手法
- ⓪使用するスライス画像枚数・番号の選定
- 粘膜部の抽出なので、歯牙などが含まれる画像は必要ない
- 全400枚 ➡ 105枚(画像番号:120-224)
- ①閾値範囲指定(ビタペックス部分のみ抽出)
- 指定前:[80 – 5442]
- 指定後:[2000 – 5442]
- ②フィルタ処理(滑らかにする)
- ③モルフォロジー演算
- 今回はオープニング処理(膨張・収縮はそれぞれ5回ずつ)
- ④境界面抽出
- (ここの実装に2週間程度掛かりました)
- 境界面を抽出するコードは「その他」にて添付
- ⓪使用するスライス画像枚数・番号の選定
- 境界面抽出後の二値画像
- 手法
-
- 3Dモデル
- ①閾値範囲指定
- 3Dモデル
⇩
-
-
- ②フィルタ処理
-
⇩
-
-
- ③モルフォロジー演算(今回はオープニング処理)
-
⇩
-
-
- ④境界面抽出
-
-
- 課題
- 粘膜部の上部のみの抽出で側面が出てきていないため、モルフォロジー演算の段階で検討の余地あり
- 穴があり面とは言えない状態なのでここを埋めて、滑らかな粘膜面を作っていく
- もう少し厚みをなくして薄い面を作れるかもしれないので、「境界面抽出」の部分も改良の余地あり
- (今後)粘膜面抽出後に元のモデルとどのように合成させるかの手法も検討していく
- 課題
反省・感想
境界面抽出コードが形になり少し安心した。
しかしまだ課題は残っているのでスピーディに解決していく。
来週の目標
- 粘膜部の側面も含んだ画像の生成
- 穴を埋め、滑らかな面を作る
- +α
- もう少し薄い面を作る
- 3Dモデルの合成手法について検討
その他
境界面抽出のコードを以下に記載する
// 境界面抽出(OpenCV)
private void btnThresholdBoundaryActionPerformed(java.awt.event.ActionEvent evt) {
int start, end;
int height = slHeight.getValue();
// int repeat = (Integer) spRepeat.getValue();
int threthBottom = slBinalizeBottom.getValue();
if (checkApplyAll.isSelected()) {
start = 0;
end = slHeight.getMaximum();
} else {
start = height;
end = height + 1;
}
System.out.println("end:" + end);
int color = Color.white.getRGB();
float[] bufData = new float[dataWidth * dataWidth * 3];
System.out.println("(Boundary)Roop start.");
for (int p = start; p <= end; p++) {
// 右パネルが「Morphology」のとき
if (tabRight.getSelectedIndex() == 1) {
bufImagePost = createImage(postMorphology[p], dataWidth, dataWidth, 255, 0);
} // 右ラベルが「Post」のとき
else {
// 左ラベルが「Pre」のとき
if (tabLeft.getSelectedIndex() == 0) {
// ループ内で都度新しい画像を作成
bufImagePost = createBinalizedImage(raw[p], dataWidth, dataWidth, threthBottom);
} // 左ラベルが「Filtered」のとき
else {
// ループ内で都度新しい画像を作成
bufImagePost = createBinalizedImage(rawFiltered[p], dataWidth, dataWidth, threthBottom);
}
}
// bufDataに値を設定
// for (int y = 0; y < dataWidth; y++) {
// for (int x = 0; x < dataWidth; x++) {
// bufData[y * dataWidth + x] = bufImagePost.getRGB(x, y) == color ? 255 : 0;
// }
// }
for (int y = 0; y < dataWidth; y++) {
for (int x = 0; x < dataWidth; x++) {
// 二値画像のピクセル値を取得 (白なら255、それ以外は0)
int pixelValue = bufImagePost.getRGB(x, y) == color ? 255 : 0;
// 各チャンネルに同じ値を設定
bufData[(y * dataWidth + x) * 3] = pixelValue;
bufData[(y * dataWidth + x) * 3 + 1] = pixelValue;
bufData[(y * dataWidth + x) * 3 + 2] = pixelValue;
}
}
// rawDataの内容をデバッグ
// System.out.println("Raw(Buf) Data: " + Arrays.toString(bufData));
// 閾値の境界を抽出
Mat boundaryImage = extractThresholdBoundary(bufData);
// System.out.println("boundaryImage OK.");
// Mat形式から再びfloat型の二次元配列に変換
postMorphology[p] = matToFloatArray(boundaryImage);
// System.out.println("postMorphology OK.");
if (p == start || p == end) {
System.out.println("p: " + p);
}
}
System.out.println("(Boundary)Roop end.");
// bufDataをファイルに書き込む
writeArrayToFile("Array_boundary/buf/bufData.txt", bufData);
// postMorphologyをファイルに書き込む
for (int i = 0; i < postMorphology.length; i++) {
writeArrayToFile("Array_boundary/postMorphology/postMorphology_" + i + ".txt", postMorphology[i]);
}
System.out.println("Boundary done!");
}
// 境界を抽出
public static Mat extractThresholdBoundary(float[] rawData) {
// 二次元配列をMatに変換
Mat inputImage = new Mat(1, rawData.length / 3, CvType.CV_32FC3);
inputImage.put(0, 0, rawData);
// 閾値の境界を抽出
Mat boundaryImage = extractThresholdBoundary(inputImage);
// System.out.println("extractThresholdBoundary1 done.");
return boundaryImage;
}
public static Mat extractThresholdBoundary(Mat inputImage) {
// 画像をグレースケールに変換
Mat grayImage = new Mat();
Imgproc.cvtColor(inputImage, grayImage, Imgproc.COLOR_RGB2GRAY);
// Sobelフィルタを適用して勾配を計算
Mat gradX = new Mat();
Imgproc.Sobel(grayImage, gradX, CvType.CV_64F, 1, 0, 3);
// 勾配の絶対値を計算
Mat absGradX = new Mat();
Core.convertScaleAbs(gradX, absGradX);
// 閾値を設定
int threshold = 50;
// 閾値を超えるピクセルを1、それ以下のピクセルを0としたマスクを作成
Mat binaryMask = new Mat();
Core.compare(absGradX, new Scalar(threshold), binaryMask, Core.CMP_GT);
// System.out.println("extractThresholdBoundary2 done.");
return binaryMask;
}
// Matからfloatへ
public static float[] matToFloatArray(Mat mat) {
// System.out.println("matToArray start.");
// float[] result = new float[(int) (mat.total() * mat.channels())];
// mat.get(0, 0, result);
int rows = mat.rows();
int cols = mat.cols();
float[] result = new float[rows * cols];
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
result[i * cols + j] = (float) mat.get(i, j)[0];
}
}
// System.out.println("matToArray done.");
return result;
}
// 配列の中身を確認
private static void writeArrayToFile(String fileName, float[] array) {
try (PrintWriter writer = new PrintWriter(new FileWriter(fileName))) {
for (float value : array) {
writer.println(value);
}
} catch (IOException e) {
e.printStackTrace();
}
}