- 영상 촬영을 하다 보면 결과물이 마음에 들지 않는 여러 이유가 있습니다.
- 애초에 잘 찍으면 되겠지만 장비나 숙련도 등의 문제로 한계가 있습니다.
- 전자현미경 사진은 여기에 시료의 상태까지 한 몫 합니다.
- 방해 요소를 제외하고 자동 명도 및 대비 보정을 하는 방법을 알아봅니다.
1. 예제 이미지

- 위와 같은 전자현미경 사진을 얻었다고 합시다.
- 전자현미경은 빛 대신 전자빔을 쏘아 매우 작은 시료를 찍는 도구입니다.
- 전자빔을 충분히 강하게 쬐면 밝고 좋은 영상을 얻을 수 있지만 시료에 따라 망가지기도 합니다.
2. ImageJ 사용 보정
-
이미지 보정 프로그램에서 대비를 높일 수 있습니다.
-
ImageJ Fiji를 사용해 개선을 시도합니다.
-
File > Open으로 파일을 불러온 후 Image > Adjust > Bright & Contrast를 실행합니다.

-
B&C라는 이름의 작은 창에 이미지를 구성하는 픽셀들의 히스토그램이 보입니다.
-
Auto를 두 번 누르면 아래와 같이 밝아지지만 대비가 개선되지 않습니다.

-
이미지 하단에 촬영 조건과 스케일바가 검정과 흰색 부분으로 붙어 있어 이 부분이 걸림돌이 됩니다.
-
이미지를 구성하는 음영 중 최대값(white)와 최소값(black)이 정해져 있는 바람에 가운데 몰린 분포가 개선되지 않는 것입니다.
-
하단을 잘라내고 재시도합니다. 메뉴 바 왼쪽의 사각형을 골라 이미지 부분만 선택합니다.

-
Image > Crop을 실행하면 아래처럼 하단이 사라집니다.

-
다시 Image > Adjust > Bright & Contrast에서 Auto를 실행하면 비로소 선명해집니다.

-
하지만 스케일 바를 비롯한 중요 정보를 잃어버린 상태입니다.
-
논문에 싣거나 내부 발표라도 하려면 스케일 바를 다시 붙여야 합니다.
-
몹시 귀찮아지고, 잘 하더라도 실수가 생길 수 있습니다.
-
무엇보다 대개 이런 이미지는 한 두 장으로 끝나지 않습니다. 자동화가 필요합니다.
3. scikit-image 사용 보정
3.1. scikit-image 설치
- 파이썬에는 이미지 처리 라이브러리가 여럿 있습니다.
- 오늘은 scikit-image를 사용해 작업합니다.
pip를 사용해 설치할 수 있습니다.
1 | !pip install scikit-image -U |
3.2. 이미지 불러오기
skimage.io의imread모듈을 사용해 이미지를 읽고imshow로 출력합니다.
1 | import numpy as np |

imread로 읽은 이미지의 정체는numpy.ndarray입니다.- 출력된 이미지의 정체는 사실
matplotlib.image.AxesImage입니다. scikit-image내부에서matplotlib을 호출하는 것입니다.imshow(img_)대신plt.imshow(img_, cmap="Greys_r")를 실행해도 같은 결과를 얻을 수 있습니다.
3.3. 이미지 및 하단 영역 크기 분리
- 이미지 크기는
.shape을 출력해 확인할 수 있습니다.
1 | img_.shape |
- 실행 결과
1 | (480, 640) |
- 이제 하단 영역의 높이를 알아볼 차례입니다.
- x = 300 지점에서 세로로 나열된 픽셀들의 line profile을 확인합니다.
1 | fig, axs = plt.subplots(ncols=2, figsize=(10, 4), constrained_layout=True) |

- 450 부근부터의 데이터 값이 모두 0입니다.
- 여기가 하단 메타데이터 영역입니다.
- 말단 50개 데이터를 출력해 0을 세어 보면 0이 31개 있습니다.
1 | img_[-50:, x] |
- 실행 결과
1 | array([118, 112, 115, 113, 111, 122, 122, 118, 111, 114, 111, 116, 122, |
- 480행 중 31행이면 16분의 1을 조금 넘습니다.
- 여유 있게 하단 15분의 1을 잘라내고 위쪽을
img, 아래쪽을desc(description)라고 부릅니다.
1 | h, w = img_.shape |

- 잘라낸 것만으로 왼쪽 그림이 선명해졌습니다.
- Matplotlib이 그림을 보여주면서 데이터의 최소값과 최대값을 자동으로 적용했기 때문입니다.
- 원본
img_와 하단을 잘라낸img의 데이터 분포를 확인합니다.
1 | fig, axs = plt.subplots(ncols=2, figsize=(10, 4), constrained_layout=True, |

- 원본이 0~252까지 범위를 가지는 데 비해 이미지 영역만 따지면 75~187에 분포하고 있습니다.
3.4. 이미지 영역에 auto contrast 적용
-
이미지의 최대값과 최소값을 0~255로 폅니다.
-
그 전에, 전자현미경 같은 디지털 영상에 흔한 salt and pepper noise 대응책을 마련합니다.
-
salt and pepper noise는 영상 위에 희고 검은 점이 흩뿌려지는 현상입니다.
-
전기 신호가 불안정하거나 원본의 대비가 잡음보다 약할 때 주로 생깁니다.

-
numpy.percentile()로 전체 데이터의 상하위 0.2%씩을 제거한 뒤, -
skimage.exposure.rescale_intensity()를 사용해 0부터 255까지 데이터의 범위를 늘려줍니다.
1 | from skimage import exposure |

3.4. 하단 영역 결합
- 이제 처음에 분리해 둔 하단 영역을 결합할 차례입니다.
numpy.vstack()을 사용합니다.- 파일 저장은
skimage.io의imsave로 실행합니다.
1 | from skimage.io import imsave |

- 스케일바를 비롯한 정보가 돌아왔습니다.
4. 주의 사항
-
분석을 열심히 하다 보면 크기를 재거나 중요 지점을 표시할 때가 있습니다.

-
여기에 위 코드를 동일하게 적용합니다.
1 | infilename = "sample_annot.png" |
- 그리고 결과를 확인해 보면 대비 보정이 적용되지 않았습니다.
1 | fig, axs = plt.subplots(ncols=2, figsize=(10, 4), constrained_layout=True) |

- 이미지 영역에 추가한 표지가 문제가 되는 경우입니다.
- salt and pepper noise를 제거하기 위해 상하위 0.2%만 제거했는데, 이 그림에는 하양과 검정으로 표현된 화살표와 글자들이 0.2%를 넘어섰기 때문에 제거되지 않고 명도의 최대값고 최소값으로 인지된 것입니다.
- 이러한 보정은 추가 정보를 기입하지 않은 상태에서 적용해야 올바르게 적용되니 주의해야 합니다.