”Defly” – программа удаления горячих пикселов/”святлечков”

Before/After (scaled)
Компьютерная программа, 2010

Извините, данная страница доступна только на английском языке.

Update: please note that now Blender supports internal denoisers that are way more sophisticated and normally work better! This page is kept for archival purposes.

Defly is an image filtering tool for removing fireflies (hot pixels) from Cycles, Octane and other computational renderings. Although this tool may help you, beware that it is not intended as an everyday production tool, but rather a proof of concept experiment.

Even though Octane has a built-in noise reduction (that seems to be based on principle explained here) it’s sometimes useful to be able to do filtering independently from rendering, to avoid lost details during animation or re-rendering animation, so I decided to keep this online for now.

Please report issues in comments below. Thank you.

Warning: Read agreement first! This program is provided as is with no any sort of warranties, so don’t put your life on it.
As there’ve been not much users noticed program is for Windows only.

How to use:
Important note: jpg causes a little blur which reduces effectiveness!
Image should be rendered without any filtering for same reason!
This was not tested, but this tool should be useless for digital camera firefly removal.

1. Load image or sequence frame that has most fireflies and sharp details
and navigate (in lower viewport) with arrow buttoons to a place that suffers from fireflies most.

2. Adjust “Remove firefly” slider so that you remove all firefly and maybe a little of brighter noise as needed:

3. Adjust “Preserve detail” slider so that you gain back thin lines or other small details that were removed by previous step if you had any:
(do not overdo with “Remove firefly” as it will require more of “Preserve details” parameter which in turn will reduce effectiveness of first one)

4. If you are doing single image press “Save this image”… Entering file name don’t forget to set extension as it will define file format.
If you are doing sequence do not save anything. Do not change parameters.
Open sequence frame that you want removal (sequence start and end filenames should appear beneath buttons)
to start with and press “Process frame range”. Frame number and extension will be added automaticaly (*.png)

Hot pixel removal principle explained:
– Program processes all non-boundary pixels of image one by one on r,g,b channels as averaged value or separated.
– If pixel is more than inverted “Remove…” value brighter than surrounding (left, right, top, bottom) pixels it is replaced with their average value if following condition is met:
– The difference between brightest and darkest pixels around (8 neighbouring pixels) must be smaller than “Preserve…” value.

Agreement:
By downloading, storing or using this program you are entering the following agreement:

You use this program at your own risk! This program comes with no warranty whatsoever.
Author is not liable for any direct/indirect damages caused by operation or inoperation or quality of this program.
You may not sell or distribute this program for any reward.
You may not separate the program from “Readme.txt” file and/or remove agreement.

Defly v0.9
Copyright © 2010 Konstantins Visnevskis, All rights reserved.

Agree and Download (~1MB)

Source code:
Note: the program was intended as a quick temporary fix.

[+] Показать

[-] Спрятать

unsigned char p[3][3][3];//channel,x,y
int mx, my, sli, sl2, cop, a[3], act;
mx = img.GetWidth();
my = img.GetHeight();
sli = 255-Slider1->GetValue();
	//Firefly threshold
sl2 = 255-Slider2->GetValue();
	//Detail preserve threshold
unsigned char *gpic=(unsigned char*)malloc(mx*my*3*sizeof(unsigned char));
gpic=img.GetData();
unsigned char *spic=(unsigned char*)malloc(mx*my*3*sizeof(unsigned char));
memcpy(spic,gpic,mx*my*3);

if(!CheckBox1->GetValue())cop=0;else cop=1;
	//evaluate RGB channels separately? (colorful fireflies?)

for(int x=1;x<mx-2;x++)
{
    for(int y=1;y<my-2;y++)
    {   //load pixels
        lo[0]=255;lo[1]=255;lo[2]=255;
        hi[0]=0;hi[1]=0;hi[2]=0;

        p[0][1][0]=gpic[3*((y-1)*mx+(x))];
        check(p[0][1][0],0);
        p[0][0][1]=gpic[3*((y)*mx+(x-1))];
        check(p[0][0][1],0);
        p[0][1][1]=gpic[3*((y)*mx+(x))];
        p[0][2][1]=gpic[3*((y)*mx+(x+1))];
        check(p[0][2][1],0);
        p[0][1][2]=gpic[3*((y+1)*mx+(x))];
        check(p[0][1][2],0);

        p[0][0][0]=gpic[3*((y-1)*mx+(x-1))];
        check(p[0][1][0],0);
        p[0][0][2]=gpic[3*((y+1)*mx+(x-1))];
        check(p[0][0][2],0);
        p[0][2][0]=gpic[3*((y-1)*mx+(x+1))];
        check(p[0][2][0],0);
        p[0][2][2]=gpic[3*((y+1)*mx+(x+1))];
        check(p[0][2][2],0);


        p[1][1][0]=gpic[3*((y-1)*mx+(x))+1];
        check(p[1][1][0],1);
        p[1][0][1]=gpic[3*((y)*mx+(x-1))+1];
        check(p[1][0][1],1);
        p[1][1][1]=gpic[3*((y)*mx+(x))+1];
        p[1][2][1]=gpic[3*((y)*mx+(x+1))+1];
        check(p[1][2][1],1);
        p[1][1][2]=gpic[3*((y+1)*mx+(x))+1];
        check(p[1][1][2],1);

        p[1][0][0]=gpic[3*((y-1)*mx+(x-1))+1];
        check(p[1][1][0],1);
        p[1][0][2]=gpic[3*((y+1)*mx+(x-1))+1];
        check(p[1][0][2],1);
        p[1][2][0]=gpic[3*((y-1)*mx+(x+1))+1];
        check(p[1][2][0],1);
        p[1][2][2]=gpic[3*((y+1)*mx+(x+1))+1];
        check(p[1][2][2],1);


        p[2][1][0]=gpic[3*((y-1)*mx+(x))+2];
        check(p[2][1][0],2);
        p[2][0][1]=gpic[3*((y)*mx+(x-1))+2];
        check(p[2][0][1],2);
        p[2][1][1]=gpic[3*((y)*mx+(x))+2];
        p[2][2][1]=gpic[3*((y)*mx+(x+1))+2];
        check(p[2][2][1],2);
        p[2][1][2]=gpic[3*((y+1)*mx+(x))+2];
        check(p[2][1][2],2);

        p[2][0][0]=gpic[3*((y-1)*mx+(x-1))+2];
        check(p[2][1][0],2);
        p[2][0][2]=gpic[3*((y+1)*mx+(x-1))+2];[collapse]
        check(p[2][0][2],2);
        p[2][2][0]=gpic[3*((y-1)*mx+(x+1))+2];
        check(p[2][2][0],2);
        p[2][2][2]=gpic[3*((y+1)*mx+(x+1))+2];
        check(p[2][2][2],2);

        //calc average around
        a[0]=(int)((int)p[0][1][0]+(int)p[0][1][2]+(int)p[0][0][1]+(int)p[0][2][1])/4;
        a[1]=(int)((int)p[1][1][0]+(int)p[1][1][2]+(int)p[1][0][1]+(int)p[1][2][1])/4;
        a[2]=(int)((int)p[2][1][0]+(int)p[2][1][2]+(int)p[2][0][1]+(int)p[2][2][1])/4;

        act=0;
        if(cop==1)
        {
            if(((int)p[0][1][1]-(int)a[0]>sli) && (hi[0]-lo[0]<sl2))
                {p[0][1][1]=(unsigned char)a[0];act++;}
            if(((int)p[1][1][1]-(int)a[1]>sli) && (hi[1]-lo[1]<sl2))
                {p[1][1][1]=(unsigned char)a[1];act++;}
            if(((int)p[2][1][1]-(int)a[2]>sli) && (hi[2]-lo[2]<sl2))
                {p[2][1][1]=(unsigned char)a[2];act++;}
        }
        else
        {
            if(((int)p[0][1][1]-(int)a[0]>sli ||
            (int)p[1][1][1]-(int)a[1]>sli ||
            (int)p[2][1][1]-(int)a[2]>sli) && (hi[0]+hi[1]+hi[2]-lo[0]-lo[1]-lo[2]<sl2*3))
                {p[0][1][1]=(unsigned char)a[0];act++;
                p[1][1][1]=(unsigned char)a[1];act++;
                p[2][1][1]=(unsigned char)a[2];act++;}
        }

        if(act>0)
        {
            spic[3*((y)*mx+(x))]=p[0][1][1];
            spic[3*((y)*mx+(x))+1]=p[1][1][1];
            spic[3*((y)*mx+(x))+2]=p[2][1][1];
        }
    }
}
img.SetData(spic);

Комментарии (13):
 

    @tester Hi, unfortunately no. I made it long ago and there was no big demand so I left it as is. Not sure I even can compile it anymore.
    Anyhow, I’m wondering, why something like this still is not implemented in Blender. The principle is really simple.

 

Добавить комментарий:  (первые два поля обязательны)

Публикуя комментарий вы соглашаетесь, что ваш IP адрес будет сохранён на данном сайте, для борьбы со спамом. Адрес вашей э-почты не будет видим публично. Имя/э-почта/линк опциональны и тоже будут сохранены. Адрес э-почты не будет показан публично, и нужен для предохранения вашего комментария от ложных заявок на авторство, а также для ответных комментариев, если выберете их получать. Узнать больше.

Комментарии показываются после модерации, что может занять некоторое время.