2015-03-27 13 views
7

Sto cercando di sfocare l'immagineJava sfocatura Immagine

int radius = 11; 
    int size = radius * 2 + 1; 
    float weight = 1.0f/(size * size); 
    float[] data = new float[size * size]; 

    for (int i = 0; i < data.length; i++) { 
     data[i] = weight; 
    } 

    Kernel kernel = new Kernel(size, size, data); 
    ConvolveOp op = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null); 
    //tbi is BufferedImage 
    BufferedImage i = op.filter(tbi, null); 

Sarà sfocare l'immagine, ma non tutti porzione dell'immagine.

enter image description here

Dove mi manca in modo che un'immagine completa sarà sfocatura. Senza alcun percorso

+0

Cosa succede se si sostituisce 'int size = radius * 2 + 1;' con valori effettivi e vedere se la modifica di questo valore cambia la casella sfocata? – npinti

+2

Vedere la sezione 'Lavorare in the Edge' in [questo articolo] (http://www.informit.com/articles/article.aspx?p=1013851&seqNum=5) per una soluzione alternativa. È necessario aumentare la dimensione dell'immagine rispetto alle dimensioni del kernel. – halex

risposta

2

Questo è dovuto al fatto che si sta utilizzando ConvolveOp.EDGE_NO_OP in questa linea:

ConvolveOp op = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null); 

Il API documentation dice:

pixel sul bordo dell'immagine di origine vengono copiati i corrispondenti pixel nella destinazione, senza modifica.

Prova EDGE_ZERO_FILL - che ti darà bordi neri.

Si può anche provare a tagliare i bordi dopo la sfocatura.

Il motivo per cui non può fare i bordi ha a che fare con il funzionamento dell'algoritmo.

+0

Con 'EDGE_ZERO_FILL' ci sarà un bordo nero attorno alla parte sfocata, che rimarrà la stessa di' EDGE_NO_OP'. – halex

+0

Sì e non voglio quel bordo nero anche –

7

Lo standard Java ConvolveOp ha solo le due opzioni EDGE_ZERO_FILL e EDGE_NO_OP. Quello che vuoi sono le opzioni dall'equivalente JAI (ConvolveDescriptor), che è EDGE_REFLECT (o EDGE_WRAP, se vuoi ripetere i pattern).

Se non si desidera utilizzare JAI, è possibile implementarlo da soli, copiando l'immagine su un'immagine più grande, allungando o avvolgendo i bordi, applicare l'opvolgimento convolvi, quindi tagliare i bordi (simile alla tecnica descritto nella sezione "Lavorare sul bordo" di the article pubblicato da @halex nella sezione commenti, ma in base a tale articolo, è anche possibile lasciare i bordi trasparenti).

Per semplicità, è possibile utilizzare solo my implementation called ConvolveWithEdgeOp che fa quanto sopra (licenza BSD).

Il codice sarà simile a quello che si aveva in origine:

// ...kernel setup as before... 
Kernel kernel = new Kernel(size, size, data); 
BufferedImageOp op = new ConvolveWithEdgeOp(kernel, ConvolveOp.EDGE_REFLECT, null); 

BufferedImage blurred = op.filter(original, null); 

Il filtro dovrebbe funzionare come qualsiasi altro BufferedImageOp, e dovrebbe funzionare con qualsiasi BufferedImage.

+0

possiamo ottenere solo sfocatura parte e coppy in un'altra immagine bufferizzata da sopra codice –

+0

@PrashantThorat Mi dispiace, non capisco la tua domanda. Il mio codice dovrebbe funzionare con qualsiasi 'BufferedImage'. – haraldK

0

Non è possibile sfocare un pixel. Sembra ovvio, ma quando ci pensi, qual è il minimo? Per sfocare un pixel, hai bisogno di pixel vicini.

Il problema qui è che ai bordi e agli angoli, i pixel hanno troppo pochi vicini: l'algoritmo di sfocatura ha pochissimi pixel da utilizzare. Non ha pixel "all'esterno" dell'immagine con cui sfocare, quindi lascerà quelli così come sono.

La soluzione è di estendere l'immagine in qualche modo (hai una più grande immagine sorgente disponibile?), O di tagliare i bit non sfocati quando hai finito. Entrambi sono essenzialmente gli stessi.

+1

Cos'è il downvote? Spiego esattamente qual è il problema. – Tomas

0

L'ho trovato una volta quando cercavo un'abilità sfocata per i documenti quando la classe ConvolveOp non la tagliava (per le ragioni per cui si sta eseguendo). Fa una sfocatura gaussiana che è la sfocatura più naturale imho ... Speriamo che ti possa aiutare. Ho recuperato da questa pagina web: Java Image Processing ...

/* 
** Copyright 2005 Huxtable.com. All rights reserved. 
*/ 

package com.jhlabs.image; 

import java.awt.image.*; 

/** 
* A filter which applies Gaussian blur to an image. This is a subclass of ConvolveFilter 
* which simply creates a kernel with a Gaussian distribution for blurring. 
* @author Jerry Huxtable 
*/ 
public class GaussianFilter extends ConvolveFilter { 

    static final long serialVersionUID = 5377089073023183684L; 

    protected float radius; 
    protected Kernel kernel; 

    /** 
    * Construct a Gaussian filter 
    */ 
    public GaussianFilter() { 
     this(2); 
    } 

    /** 
    * Construct a Gaussian filter 
    * @param radius blur radius in pixels 
    */ 
    public GaussianFilter(float radius) { 
     setRadius(radius); 
    } 

    /** 
    * Set the radius of the kernel, and hence the amount of blur. The bigger the radius, the longer this filter will take. 
    * @param radius the radius of the blur in pixels. 
    */ 
    public void setRadius(float radius) { 
     this.radius = radius; 
     kernel = makeKernel(radius); 
    } 

    /** 
    * Get the radius of the kernel. 
    * @return the radius 
    */ 
    public float getRadius() { 
     return radius; 
    } 

    public BufferedImage filter(BufferedImage src, BufferedImage dst) { 
     int width = src.getWidth(); 
     int height = src.getHeight(); 

     if (dst == null) 
      dst = createCompatibleDestImage(src, null); 

     int[] inPixels = new int[width*height]; 
     int[] outPixels = new int[width*height]; 
     src.getRGB(0, 0, width, height, inPixels, 0, width); 

     convolveAndTranspose(kernel, inPixels, outPixels, width, height, alpha, CLAMP_EDGES); 
     convolveAndTranspose(kernel, outPixels, inPixels, height, width, alpha, CLAMP_EDGES); 

     dst.setRGB(0, 0, width, height, inPixels, 0, width); 
     return dst; 
    } 

    public static void convolveAndTranspose(Kernel kernel, int[] inPixels, int[] outPixels, int width, int height, boolean alpha, int edgeAction) { 
     float[] matrix = kernel.getKernelData(null); 
     int cols = kernel.getWidth(); 
     int cols2 = cols/2; 

     for (int y = 0; y < height; y++) { 
      int index = y; 
      int ioffset = y*width; 
      for (int x = 0; x < width; x++) { 
       float r = 0, g = 0, b = 0, a = 0; 
       int moffset = cols2; 
       for (int col = -cols2; col <= cols2; col++) { 
        float f = matrix[moffset+col]; 

        if (f != 0) { 
         int ix = x+col; 
         if (ix < 0) { 
          if (edgeAction == CLAMP_EDGES) 
           ix = 0; 
          else if (edgeAction == WRAP_EDGES) 
           ix = (x+width) % width; 
         } else if (ix >= width) { 
          if (edgeAction == CLAMP_EDGES) 
           ix = width-1; 
          else if (edgeAction == WRAP_EDGES) 
           ix = (x+width) % width; 
         } 
         int rgb = inPixels[ioffset+ix]; 
         a += f * ((rgb >> 24) & 0xff); 
         r += f * ((rgb >> 16) & 0xff); 
         g += f * ((rgb >> 8) & 0xff); 
         b += f * (rgb & 0xff); 
        } 
       } 
       int ia = alpha ? PixelUtils.clamp((int)(a+0.5)) : 0xff; 
       int ir = PixelUtils.clamp((int)(r+0.5)); 
       int ig = PixelUtils.clamp((int)(g+0.5)); 
       int ib = PixelUtils.clamp((int)(b+0.5)); 
       outPixels[index] = (ia << 24) | (ir << 16) | (ig << 8) | ib; 
       index += height; 
      } 
     } 
    } 

    /** 
    * Make a Gaussian blur kernel. 
    */ 
    public static Kernel makeKernel(float radius) { 
     int r = (int)Math.ceil(radius); 
     int rows = r*2+1; 
     float[] matrix = new float[rows]; 
     float sigma = radius/3; 
     float sigma22 = 2*sigma*sigma; 
     float sigmaPi2 = 2*ImageMath.PI*sigma; 
     float sqrtSigmaPi2 = (float)Math.sqrt(sigmaPi2); 
     float radius2 = radius*radius; 
     float total = 0; 
     int index = 0; 
     for (int row = -r; row <= r; row++) { 
      float distance = row*row; 
      if (distance > radius2) 
       matrix[index] = 0; 
      else 
       matrix[index] = (float)Math.exp(-(distance)/sigma22)/sqrtSigmaPi2; 
      total += matrix[index]; 
      index++; 
     } 
     for (int i = 0; i < rows; i++) 
      matrix[i] /= total; 

     return new Kernel(rows, 1, matrix); 
    } 

    public String toString() { 
     return "Blur/Gaussian Blur..."; 
    } 
} 
0

Se avete a che fare spesso con le immagini nella propria applicazione, si può prendere in considerazione utilizzando l'API ImageJ: E 'confezioni funzionalità su un bel po' di compiti di elaborazione delle immagini, compresa la sfocatura.

loro filtro Controllo sfocatura sarà offuscare fino al bordo dell'immagine, apportando le seguenti ipotesi

{...} si presuppone che out-of-immagine pixel hanno un valore pari al più vicino pixel bordo {...}

Anche se non si desidera modificare il codice per utilizzare l'API ImageJ, si può ancora trovare l'ipotesi sopra utile a risolvere il tuo problema.

Per ulteriori informazioni, controllare il filtro GaussianBlur nella documentazione delle API: http://rsb.info.nih.gov/ij/developer/api/ij/plugin/filter/GaussianBlur.html

1

È possibile utilizzare libreria OpenCV per rendere completa sfocatura dell'immagine.