This approach to border deringing uses [linear least squares](https://www.gnu.org/software/gsl/doc/html/lls.html) to find a proper adjustment.

SinglePlane does simple linear regression between each line and the first clean line. MultiPlane does the same with multiple linear regression using all three planes. SinglePlaneLimited does this for each pixel individually using only the nearest pixels defined by ref_line_size. SinglePlaneWeighted is SinglePlaneLimited with bilateral filter style weighting for distance and difference. SinglePlaneDebug is the same as SinglePlane, but saves adjustment values to frame props instead of applying them.

SinglePlaneLimited and SinglePlaneWeighted are more experimental and should be used with care.

The frame props generated by SinglePlanedebug are:
* `BoreAdjustment`
* `BoreCovariance`
* `BoreSumSquares`
These are in order of operation, i.e. top, bottom, left, right, each from innermost to outermost line.

## Requirements
* [GSL](https://www.gnu.org/software/gsl/)

## VapourSynth usage

```
core.bore.SinglePlane(clip clip, int left=0, int right=0, int top=0, int bottom=0, clip weight_mask=None, int plane=0)
core.bore.MultiPlane(clip clip, int left=0, int right=0, int top=0, int bottom=0, clip weight_mask=None, int plane=0)
core.bore.SinglePlaneLimited(clip clip, int left=0, int right=0, int top=0, int bottom=0, clip weight_mask=None, int ref_line_size=100, int plane=0)
core.bore.SinglePlaneWeighted(clip clip, int left=0, int right=0, int top=0, int bottom=0, clip weight_mask=None, float sigmaS=50.0, float sigmaR=0.5, float sigmaD=1.5, int ref_line_size=100, int plane=0)
core.bore.SinglePlaneDebug(clip clip, int left=0, int right=0, int top=0, int bottom=0, clip weight_mask=None, int plane=0)
```

## AviSynth+ usage

```
bore_SinglePlane(clip input, int "left", int "right", int "top", int "bottom", clip "weight_mask", int "plane")
bore_MultiPlane(clip input, int "left", int "right", int "top", int "bottom", clip "weight_mask", int "plane")
bore_SinglePlaneLimited(clip input, int "left", int "right", int "top", int "bottom", clip "weight_mask", int "plane", int "ref_line_size")
bore_SinglePlaneWeighted(clip input, int "left", int "right", int "top", int "bottom", clip "weight_mask", int "plane", int "ref_line_size", float "sigmaS", float "sigmaR", float "sigmaD")
bore_SinglePlaneDebug(clip input, int "left", int "right", int "top", int "bottom", clip "weight_mask", int "plane")
```

* `clip`: 32-bit float clip.
* `left = 0`, `right = 0`, `top = 0`, `bottom = 0`: number of lines from each border to adjust.
* `weight_mask = None`: 32-bit gray mask with pixel weights, useful for discluding edges and clipped areas from adjustment calculation. If more than one plane exists, only the first one is used, so it needs to match the to-be-adjusted plane's resolution.
* `plane = 0`: Plane to adjust.
* `sigmaS = 50, sigmaR = 0.5, sigmaD = 1.5`: SinglePlaneWeighted's smoothing parameters, same as a bilateral filter's, sigmaR is difference between pixels in same line, sigmaD is difference between adjustments compared to current pixel and its neighbor.
* `ref_line_size = 100`: Reference line size for SinglePlaneLimited/Weighted. The actual size is `2 * ref_line_size + 1`.

# Compilation

```sh
meson build
ninja -C build
```

In Windows you can configure MinGW and run the meson build, but the easiest way is to [download LLVM](https://github.com/llvm/llvm-project/releases) (*-win64.exe file) and install with the **path option ticked**, then run:

```ps
clang -O2 -march=native -shared -o bore.dll -I"C:\Program Files\VapourSynth\sdk\include" src\bore.c
```
