Ryo-Ito / brain_segmentation

Implementation of VoxResNet for 3D brain segmentation
MIT License
66 stars 17 forks source link

Missing one step in pre-processing #6

Closed John1231983 closed 6 years ago

John1231983 commented 7 years ago

Hi, the pre-processing step in the paper said that

pre-processed the images by subtracting Gaussian smoothed image and applying Contrast-Limited Adaptive Histogram Equalization (CLAHE)

It means that the original images are subtracting with Gaussian smoothed, then applied CLAHE for the result of Gaussian smooth. However, your preprocessing did not consider the Gaussian smoothed step. Are you missing this step or you ignore it? I think the performance depends on the step also. If it is possible, could you add it in your code? Thanks

Ryo-Ito commented 7 years ago

Sorry, I missed the line. I fixed the code to include the step. Thanks for your comment, it actually improved the segmentation accuracy of CSF.

John1231983 commented 7 years ago

You are welcome. One more thing, that may be help you improve the performance.

  1. The normalization and histogram enhancement are processed slice by slice, instead of whole volumetric data
  2. The Gaussian filter is 2D gaussian with sigma is (5,5) and kernel 31x31

This is my pre-processing for above mentioned. Could you try this way in your database and let me know which ones give better performance? Thanks

for i in range(data.shape[0]): #Depthxheightxweight
    data_i = data[i, :, :]
    data_i_smooth = cv2.GaussianBlur(data_i , (31, 31), 5)
    data_i  = data_i  - data_i_smooth
    data_i = (data_i - data_i.mean()) / data_i.std()  
    data_i = (data_i - np.min(data_i)) / (np.max(data_i) - np.min(data_i)) # convert to [0,1]
    data_i = np.array(data_i * 255, dtype=np.uint8) #Convert to [0,255]
    clahe_data = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(16,16))  
    data_i = clahe_data.apply(data_i)
    data[i, :, :] = data_i 
Ryo-Ito commented 7 years ago

Unfortunately, the slice-by-slice processing worsened the result of CSF. I will stick with the volumetric processing. Considering that the network performs volumetric convolutions, it is more natural for me than the slice-by-slice one.

John1231983 commented 7 years ago

Thanks for your information. I guess the reason is from CLAHE processing. When you use slice-by-slice, do you still use your CLAHE sitk.AdaptiveHistogramEqualization or my above code? In my opinion, the slice-by-slice processing is mentioned in at least two papers and it can avoid some variance between slices, i.e in T1_IR

Ryo-Ito commented 7 years ago

I used CLAHE from scikit-image for the slice-by-slice processing, skimage.exposure.equalize_adapthist.

John1231983 commented 7 years ago

I see, I have been used the function before but it is not so correct. In the paper, they mention about clipLimit=2. Hence, I think it is better use

    data_i = (data_i - np.min(data_i)) / (np.max(data_i) - np.min(data_i)) # convert to [0,1]
    data_i = np.array(data_i * 255, dtype=np.uint8) #Convert to [0,255]
    clahe_data = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(16,16))  
    data_i = clahe_data.apply(data_i)

Let's try above histogram equalization and I guess it will be better.

Ryo-Ito commented 7 years ago

I thought the clip limit is supposed to be in the range from 0 to 1 (ref). What's the meaning of clipLimit=2?

John1231983 commented 7 years ago

Yes, you are right when you use skimage.exposure.equalize_adapthist. However, in the cv2.createCLAHE , the value can be bigger than one ref this is setting of the original paper

Ryo-Ito commented 7 years ago

I tested CLAHE in opencv2 (cv2.createCLAHE) as you advised me, but it still didn't work so well. I uploaded the preprocessing code (preprocess.py) under "slice" branch. It would be helpful if you could check and see what I am doing wrong.

John1231983 commented 7 years ago

Sorry for reply late. I also tried both slice-by-slice processing and whole image processing. I found that the whole image processing makes consistent results than slice-by-slice processing. Although the paper mentioned about slice-by-slice, I think he used MATLAB and he followed the original paper. One more thing I want to comment here. The paper used the deeply supervised loss that similar loss_weight in CAFFE. It chooses as 0.1 for c1,c2,c3,c4. However, I did not see that in your implementation. I think your result will be better if you consider it because the purpose of this way is for training in limited data.

Ryo-Ito commented 7 years ago

Thanks for your tries. I decided to keep my code using the whole image processing. As you mentioned in the second paragraph, my code does not set coefficients for the auxiliary classifiers. But I actually tried exponential decay $w=1e-3 + 0.5^(n / N)$ and linear decay $w=1e-3 (n / N) + 1 (1 - n / N)$ on my own, which both worsened the segmentation result. I will try constant coefficients smaller than 1 next time.