web-dev-qa-db-fra.com

Lissage des bords d'une image binaire

Comment lisser les bords de cette image binaire des vaisseaux sanguins obtenue après seuillage.

enter image description here

J'ai essayé une méthode quelque peu similaire à cette méthode mais je n'ai pas vraiment obtenu le résultat attendu.

enter image description here

Voici le code:

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)  

Que peut-on faire pour améliorer le lissage de ces bords durs?

[~ # ~] modifier [~ # ~]

Je voudrais lisser les bords quelque chose comme http://pscs5.tumblr.com/post/6028457054 . Comment faire cela dans OpenCV?

13
Abdul Fatir

Voici le résultat que j'ai obtenu avec votre image: enter image description here

Ma méthode est principalement basée sur plusieurs cv::medianBlurappliqué sur une image agrandie.

Voici le code:

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);

Les bords dentelés sont dus au seuillage. Si vous êtes à l'aise avec une image de sortie non binaire (c'est-à-dire avec 256 nuances de gris), vous pouvez simplement la supprimer et vous obtenez cette image: enter image description here

18
Sunreef

Vous pouvez dilater puis éroder les zones 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)  

FromTo

MODIFIER avec une échelle de 4 facettes avant le truc enter image description here

4
user5698387

j'ai fait quelques modifications sur @dhanushka's réponse à une autre question et obtenir ces images.

Désolé, c'est du code C++ mais peut-être que vous le convertirez en Python.

enter image description here

Vous pouvez modifier les paramètres ci-dessous pour obtenir des résultats différents.

// 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

enter image description here

#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);
}
3
sturkmen

Ce que vous pouvez faire, c'est augmenter la résolution de votre image (par exemple, la doubler ou la tripler en utilisant resize). Après cela, l'érosion et la dilatation décrites dans l'autre réponse ci-dessus conduiront à des résultats plus fins.

3
tfv

Vous avez très probablement d'abord obtenu une image en échelle de gris des vaisseaux sanguins, puis seuillée. Il semble toujours non lisse, car l'image d'origine de l'échelle de gris avait du bruit à l'intérieur. Demander maintenant un lissage des bords entraînera une résolution inférieure. Par exemple, la dilution et l'érosion proposées dans ne autre réponse pourraient fusionner les récipients voisins dans l'étape de dilution qui ne peuvent alors plus être séparés dans l'étape d'érosion.

Il peut être préférable de supprimer d'abord le bruit dans l'image en niveaux de gris (c'est-à-dire d'y faire un lissage) et de faire le seuillage comme dernière étape.

Parce que vous n'avez pas fourni l'image d'échelle de gris, j'ai effectué un lissage doux (environ une largeur de pixel) ici sur l'image binaire et effectué à nouveau un seuillage.

enter image description here

J'ai fait un lissage (avec un noyau gaussien de taille fixe) et un seuillage (avec un paramètre de seuillage). Je vous suggère de le faire sur les données d'image en niveaux de gris et d'ajuster les deux paramètres jusqu'à ce que le résultat vous plaise.

Code Matlab en cas d'intérêt:

% 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');
2
Trilarion