Сглаживание краев двоичного изображения
Как сгладить края этого бинарного изображения кровеносных сосудов, полученного после установления порога.
![enter image description here]()
Я попробовал метод, похожий на этот метод, но не получил ожидаемого результата.
![enter image description here]()
Вот код:
import cv2
import numpy as np
INPUT = cv2.imread('so-br-in.png',0)
MASK = np.array(INPUT/255.0, dtype='float32')
MASK = cv2.GaussianBlur(MASK, (5,5), 11)
BG = np.ones([INPUT.shape[0], INPUT.shape[1], 1], dtype='uint8')*255
OUT_F = np.ones([INPUT.shape[0], INPUT.shape[1], 1],dtype='uint8')
for r in range(INPUT.shape[0]):
for c in range(INPUT.shape[1]):
OUT_F[r][c] = int(BG[r][c]*(MASK[r][c]) + INPUT[r][c]*(1-MASK[r][c]))
cv2.imwrite('brain-out.png', OUT_F)
Что можно сделать, чтобы улучшить сглаживание этих резких краев?
EDIT
Я бы хотел сгладить края примерно как http://pscs5.tumblr.com/post/60284570543. Как это сделать в OpenCV?
Ответы
Ответ 1
Вот результат, который я получил с вашим изображением: ![введите описание изображения здесь]()
Мой метод в основном основан на нескольких cv::medianBlur
, применяемых на увеличенном изображении.
Вот код:
cv::Mat vesselImage = cv::imread(filename); //the original image
cv::threshold(vesselImage, vesselImage, 125, 255, THRESH_BINARY);
cv::Mat blurredImage; //output of the algorithm
cv::pyrUp(vesselImage, blurredImage);
for (int i = 0; i < 15; i++)
cv::medianBlur(blurredImage, blurredImage, 7);
cv::pyrDown(blurredImage, blurredImage);
cv::threshold(blurredImage, blurredImage, 200, 255, THRESH_BINARY);
Неровные края связаны с порогом. Если вам комфортно выводить изображение, не являющееся двоичным (т.е. с 256 оттенками grAy), вы можете просто удалить его, и вы получите это изображение: ![введите описание изображения здесь]()
Ответ 2
Затем вы можете разложить области http://docs.opencv.org/2.4/doc/tutorials/imgproc/erosion_dilatation/erosion_dilatation.html.
import cv2
import numpy as np
blur=((3,3),1)
erode_=(5,5)
dilate_=(3, 3)
cv2.imwrite('imgBool_erode_dilated_blured.png',cv2.dilate(cv2.erode(cv2.GaussianBlur(cv2.imread('so-br-in.png',0)/255, blur[0], blur[1]), np.ones(erode_)), np.ones(dilate_))*255)
![To]()
ИЗМЕНИТЬ, когда шкала закрыта с 4 перед материалом ![введите описание изображения здесь]()
Ответ 3
Что вы можете сделать, это увеличить разрешение вашего изображения (например, удвоить или утроить его с помощью resize
). После этого эрозия и дилатация, как описано в другом ответе выше, приведут к более тонким результатам.
Ответ 4
я внесла некоторые изменения в @dhanushka ответить на другой вопрос и получить эти изображения.
Извините, это код на С++, но, возможно, вы преобразуете его в Python.
![введите описание изображения здесь]()
Вы можете изменить параметры ниже, чтобы получить разные результаты.
// contour smoothing parameters for gaussian filter
int filterRadius = 10; // you can try to change this value
int filterSize = 2 * filterRadius + 1;
double sigma = 20; // you can try to change this value
![введите описание изображения здесь]()
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main( int argc, const char** argv )
{
Mat im = imread(argv[1], 0);
Mat cont = ~im;
Mat original = Mat::zeros(im.rows, im.cols, CV_8UC3);
Mat smoothed = Mat(im.rows, im.cols, CV_8UC3, Scalar(255,255,255));
// contour smoothing parameters for gaussian filter
int filterRadius = 5;
int filterSize = 2 * filterRadius + 1;
double sigma = 10;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
// find contours and store all contour points
findContours(cont, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_NONE, Point(0, 0));
for(size_t j = 0; j < contours.size(); j++)
{
// extract x and y coordinates of points. we'll consider these as 1-D signals
// add circular padding to 1-D signals
size_t len = contours[j].size() + 2 * filterRadius;
size_t idx = (contours[j].size() - filterRadius);
vector<float> x, y;
for (size_t i = 0; i < len; i++)
{
x.push_back(contours[j][(idx + i) % contours[j].size()].x);
y.push_back(contours[j][(idx + i) % contours[j].size()].y);
}
// filter 1-D signals
vector<float> xFilt, yFilt;
GaussianBlur(x, xFilt, Size(filterSize, filterSize), sigma, sigma);
GaussianBlur(y, yFilt, Size(filterSize, filterSize), sigma, sigma);
// build smoothed contour
vector<vector<Point> > smoothContours;
vector<Point> smooth;
for (size_t i = filterRadius; i < contours[j].size() + filterRadius; i++)
{
smooth.push_back(Point(xFilt[i], yFilt[i]));
}
smoothContours.push_back(smooth);
Scalar color;
if(hierarchy[j][3] < 0 )
{
color = Scalar(0,0,0);
}
else
{
color = Scalar(255,255,255);
}
drawContours(smoothed, smoothContours, 0, color, -1);
}
imshow( "result", smoothed );
waitKey(0);
}
Ответ 5
Вы, скорее всего, сначала получили изображение в масштабе шкалы кровеносных сосудов, а затем порог. Он по-прежнему выглядит негладким, потому что исходное изображение в сером цвете имеет шум внутри. Теперь попросить о сглаживании краев приведет к более низкому разрешению. Например, разбавление и эрозия, предложенные в другом ответе, могут сливать соседние сосуды на стадии разбавления, которые затем не могут быть снова разделены на этапе эрозии.
Может быть предпочтительнее сначала удалить шум в изображении с серой шкалой (а также сделать сглаживание) и сделать пороговое значение в качестве последнего шага.
Поскольку вы не доставляли изображение с серой шкалой, я выполнил мягкое сглаживание (около одной ширины пикселя) здесь на двоичном изображении и снова выполнил пороговое значение.
![введите описание изображения здесь]()
Я сделал сглаживание (с гауссовским ядром фиксированного размера) и пороговое значение (с параметром порога). Я предлагаю вам сделать это в данных изображения в оттенках серого и настроить два параметра, пока вам не понравится результат.
Код Matlab в случае, если он представляет интерес:
% read
img = imread('YyNQV.png');
img = double(img(:, :, 1) ~= 255); % png is RGB -> binary
% smooth
kernel = fspecial('gaussian', 10, 1.5);
kernel = kernel / sum(kernel(:)); % normalize to 1
img_smooth = conv2(img, kernel, 'same');
% binarize again
threshold = 0.4; % experiment with values between 0 and 1
img_smooth_threshold = img_smooth > threshold;
% save (exchange black and white)
imwrite(~img_smooth_threshold, 'YyNQV_smooth.png');