Release of G'MIC 3.0

Hmm, I don’t know if that is the reason for using wrong header files. I think more the reason is the location of opencv (3) and opencv4

/opt/local/include/opencv2

/opt/local/include/opencv4/opencv2

Even depending on the compiler chosen one or the other are taken!

Perhaps it would be better to have the older version (3) also in a subfolder, e.g. /opt/local/include/opencv2/opencv2 !

Sure enough: when I build in trace mode there link error goes away. It’s likely a header issue.

1 Like

Nicely nasty error! Good for a change!

1 Like

Hello,
@David_Tschumperle
G'MIC - GREYC's Magic for Image Computing: A Full-Featured Open-Source Framework for Image Processing - Reference Documentation - display_camera should be noted as OpenCV-dependent (if I am not mistaken).

Hey guys, so sorry for the slow reply!

@afre and @David_Tschumperle, as you probably know, once you upload a file towards FossHub, we scan it using Jotti’s malware scan service - you can read about it here

Long story short, there are some rules, so when several antivirus engines flag the file as malware, we disable the download automatically for our visitor’s safety. The same thing happened with this file.

We have zero control over the anti-malware vendors, so you will have to get in touch with each one of them if there is a problem. Very frustrating as sometimes browsers will also choose to block your download.

What we can do is disable the antivirus scan for your project. We do not recommend this as thousands of users are checking the scan results daily. However, each project owner can decide what to do in this case. We made this option available as a last resort.

Thanks @FossHub, I don’t really know what to do to be honest.

  • I don’t know why the antivirus think G’MIC binaries are virus. I’d be interested to know if this is due to some heuristics or what… I compile the binaries on a Windows VM. On this VM, I do nothing but compiling and testing the plug-in under G’MIC (I don’t even launch a web browser on it), so I really doubt I got a virus. And even if this was the case, I doubt this virus would replicate itself in a binary I compile with g++.

  • If we deactivate the antivirus protection on Fosshub, it could look a bit strange and unsafe. So I don’t think this is a solution.

  • We should probably try to make those antivirus accept the G’MIC binaries as safe. I don’t know how to do that and how to contact them to convince it’s safe. And as it concerns only the .dll files of the G’MIC libraries (so probably one of the less downloaded file), I’m not sure this is worth the time spent.

I’ll be waging a bet here, and I think it’s because G’MIC has codes similar to ones that are executed by malwares or something like that. I don’t think that’s a good answer nor I want to insinuate that @David_Tschumperle provides malwares. In other words, it comes down to heuristics.

@David_Tschumperle

I doubt you have a virus. The only file is this one: “gmic_2.9.6_lib_win64.zip” So, most likely a false positive. Depending on what changes you’re making next in a future release, this might not happen again.

I agree. Just a friendly FYI that we will not disable the antivirus without your consent.

From experience, I can tell you that most AV vendors will respond and whitelist (if that’s the case) a specific file. However, if it is being detected again, you will need to repeat the procedure. There’s no such thing as a permanent whitelist.

My suggestion would be to upload the file with problems on VirusTotal before releasing a new version. Luckily you have only one file with a false positive. Make some changes until you get fewer detections. You will lose some of your precious time but will know what to avoid in the future. A few projects hosted on FossHub had this issue in the past, and this was the final solution.

I might add that FossHub was also affected by this, browsers blocking specific downloads from us, so in the end, it is a frustrating experience for both devs and us. However, we agree that safety should be first (again, a good reason to disable the downloads on our end).

This is what RT and dt devs have done on numerous occasions.

1 Like

@David_Tschumperle Having just written gcd_boxfilter_local, I wonder if there’s already a fast/native alternative? It’s a box filter with kernel window size specified per-pixel by a reference image - similar to “Variable Blur” in gimp (although approximate). Extremely simple code too, with no penalty for kernel size.

Although it’s quick enough for my uses, I would always prefer a much faster version if available…

Yes, I think so. I may give a try later today, but obviously, what I see is:

  1. f.. ">i+j(-1)" is basically equivalent to cumulate x, same for the Y part.
  2. You’ve decided to implement your filtering as a separable process, but here, I guess this can be done at once easily. When you have the XY-accumulation image J of an input image I, the mean of the values of I lying in a rectangle (x0,y0)-(x1,y1) is indeed :
    (J(x1,y1) + J(x0-1,y0-1) - J(x1,y0-1) - J(x0-1,y1))/S
    where S = (x1 - x0 + 1)*(y1 - y0 + 1) is the number of pixels in the rectangle.

Knowing that should let you implement this with a single fill command.

Actually, this is a really interesting idea, so it deserves to be in the G’MIC stdlib.
Another good property of the box filter is that iterating a box filter 4 or 5 times with the same radius is roughly equivalent to a gaussian filter (so, with smooth transitions).
This could then lead to a super-cool adaptive gaussian filter.

1 Like

I will reply in full later, but yes to be accurate we would need to use a 2D SAT and handle the boundary complications (it’s not truly separable). I believe it possible and will have a go later. Got to rush out for now!

Also, I don’t see why interpolation=1 here. Doing this will slow down the access to pixel values, and I don’t think this is actually necessary in that case.

I’ve made a quick test:

foo :
  repeat $! l[$>]
    +gradient_norm. f. "1/(1+i^0.5)" n. 0,2
    repeat 2
      +cumulate[0] xy
      f[0] "
        const boundary = 1;
        const interpolation = 1;  # Use it because N below is float-valued
        N = i(#1,x,y,0,0);
        !N?i:(
          x0 = x - N;
          y0 = y - N;
          x1 = x + N;
          y1 = y + N;
          area = (2*N+1)^2;
          x0m1 = x0 - 1;
          y0m1 = y0 - 1;
          (i(#-1,x1,y1) + i(#-1,x0m1,y0m1) - i(#-1,x0m1,y1) - i(#-1,x1,y0m1))/area
        )"
      rm.
    done
    rm.
  endl done

Already interesting, but I guess this could be improved by choosing better x0,y0,x1,y1 for each pixel (possibly non centered ?).

Now, if i try to make x0,y0,x1,y1 adaptive, then use a separable approach, it gives me quite interesting results.
I’ve tried this:

foo :
  +cumulate. x
  f[0] "
    const boundary = 1;
    for (x0 = x, x0>=0 && abs(i(x0) - i)<20, --x0);
    for (x1 = x, x1<w && abs(i(x1) - i)<20, ++x1);
    (i(#1,x1) - i(#1,x0 - 1))/(x1 - x0 + 1)"
  rm.
  +cumulate. y
  f[0] "
    const boundary = 1;
    for (y0 = y, y0>=0 && abs(i(x,y0) - i)<20, --y0);
    for (y1 = y, y1<h && abs(i(x,y1) - i)<20, ++y1);
    (i(#1,x,y1) - i(#1,x,y0 - 1))/(y1 - y0 + 1)"
  rm.

and get :

$ gmic sp colorful +foo

2 Likes

Both of you, thanks for entertaining my PM questions on SAT and G’MIC syntax.

After your prompting and the bug fix, I have been using cumulate because it is faster.

That is my influence, thinking that separation would speed things up, and as we are discussing, make the filter more adaptable.

I considered this, and have had a question that I have been meaning to ask for a while. If I iterate a 3x3 box filter multiple times (e.g. boxfilter), I do get a blur estimate; but blur can do smaller standard deviations. Would it be possible to box filter windows smaller than 3x3 to approximate smaller blurs? Would that involve interpolation?

Yes, this is closer to what I had in mind.

It stumbles if I do

gmic sp colorful / {iM} +foo

I’ll obviously be delighted if we get a native (or at least much faster) version!

I’ll need to properly understand your example there, but suspect separated will not be quite as useful (unless you’ve done something clever). It works perfectly fine as a straightforward box filter where all windows are the same size, but not so for differing per-pixel window sizes.

With my own filter gcd_boxfilter_local the problems become apparent when close neighbouring window sizes differ greatly. The end result is streaks in whichever axis is processed last:

gmic 512,512,1,1 circle. 50%,50%,50,1,1 sp cat gcd_boxfilter_local.. .

separable

I won’t be surprised if you’ve realised something I haven’t which deals with that, but my own conclusion is we need a 2D summed area with correct boundary handling. The boundaries should be possible but tricky. I’ll probably write a version of that myself as a point of reference (I hope this week).

Edit: another good sanity check - especially for boundaries - is to use it with a constant reference image i.e. +f 50 (i.e. a normal box filter).

Even though gcd_boxfilter_local streaks, [Edit See (1) at footer.] it is still more stable than the generic SAT driven box filter. I am not sure what @garagecoder is doing that makes it behave better. I.e., substituting his box filter in my guided filter doesn’t cause range disparities (impulse noise). Mine does, even though it is a simple 2D SAT driven box filter injected into afre_gui0.

afre_box0 : check ${1=1}>=1
  repeat $! l[$>]
    b={$1*2+2} r {[w,h]+$b},100%,100%,0,1,0.5,0.5
    cumulate xy
    f "begin(const boundary=1; const R=$1; const S=-R-1;
      const A=sqr(R*2+1)); (j(R,R)+j(S,S)-j(S,R)-j(R,S))/A
    " r {[w,h]-$b},100%,100%,0,0,0.5,0.5
  endl done

afre_gui0 with changes in smoothing: original, 1e-2, 1e-1, 1e0 and 1e1. The latter two have peaks only in the whiskers.

gmic sp tiger repeat 4 +Agui0[0] 1,1e{$^>-2} done c 0,255 a z xz s z a y o tigers.png

tigers

Note that boxfilter, blur and my custom convolve driven methods don’t exhibit such artifacts.


Edit (1) Correction: the command that works error free for me is gcd_satboxfilter, the precursor of gcd_boxfilter_local.

Not surprising at all. Usually, when smoothing an image, it’s good to have a smoothing geometry that is smooth itself, to avoid the apparition of artefacts (mostly discontinuities that are too contrasted).
I would suggest you store the smoothing “radius” of each pixel in an image, then blur it (with gaussian blur) before using the smothed radii to actually filter the image.

Something like this:

foo : check "${1=2}>0"
  repeat $! l[$>]

    # Determine pixelwise smoothing radius.
    +b. 2 gradient_norm. f. "$1/(1+i^0.5)"

    # Iterate adaptive box filter.
    repeat 2
      +cumulate[0] xy
      f[0] "
        const boundary = 1;
        const interpolation = 1; # R is float-valued
        R = i(#1,x,y,0,0);
        R2p1 = R*2 + 1;
        R>0?(
          x0 = x - R - 1;
          y0 = y - R - 1;
          x1 = x + R;
          y1 = y + R;
          (i(#-1,x1,y1) + i(#-1,x0,y0) - i(#-1,x1,y0) - i(#-1,x0,y1))/R2p1^2;
        ):i"
      rm.
    done
    k[0]
    c 0,255
  endl done