Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimization pass #58

Merged
merged 48 commits into from
Nov 12, 2016
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
d870aa6
Parallelized and optimized corner response calculation.
ljubobratovicrelja Sep 29, 2016
daf4e92
Refactoring of extractCorners.
ljubobratovicrelja Oct 1, 2016
958f5a9
Refactoring rgb(bgr)2gray.
ljubobratovicrelja Oct 1, 2016
b6ac069
Refactoring rgb2hsv.
ljubobratovicrelja Oct 1, 2016
7da0159
Refactoring hsv2rgb.
ljubobratovicrelja Oct 1, 2016
5658eb9
uninitializedArray --> uninitializedSlice.
ljubobratovicrelja Oct 1, 2016
0fc5b01
Refactoring yuv2rgb, overall module cleanup.
ljubobratovicrelja Oct 1, 2016
5970cb2
Added static slice packing helpers.
ljubobratovicrelja Oct 2, 2016
720fd50
Extracted ndIter kernel lambdas to functions.
ljubobratovicrelja Oct 2, 2016
21f6118
div by 100.0 replaced with mul by 0.01.
ljubobratovicrelja Oct 2, 2016
c3cb076
Extracted kernels to functions, added fastmath.
ljubobratovicrelja Oct 2, 2016
5611394
Replaced std.math.sqrt with llvm_sqrt.
ljubobratovicrelja Oct 2, 2016
deaeed9
Added mcpu=native flag.
ljubobratovicrelja Oct 2, 2016
e5228ed
Randomized hsv values.
ljubobratovicrelja Oct 2, 2016
aead0ad
Loop refactoring.
ljubobratovicrelja Oct 2, 2016
09b5f1f
Fixed non-contiguous loop iteration fail.
ljubobratovicrelja Oct 2, 2016
444f13a
Added nothrow and nogc.
ljubobratovicrelja Oct 6, 2016
e4075f1
Refactoring of convolution functions.
ljubobratovicrelja Oct 6, 2016
a486d08
Merge branch 'master' into optimization-patch-2
ljubobratovicrelja Oct 9, 2016
a58eb04
Merge branch 'master' into optimization-patch-2
ljubobratovicrelja Oct 10, 2016
7ab3a0b
Added tensor border extraction.
ljubobratovicrelja Oct 11, 2016
f352a77
Added in contract for non-matrix tensors.
ljubobratovicrelja Oct 11, 2016
4a9722a
Reorganized templates in boundary conditions to support lazy tensors.
ljubobratovicrelja Oct 11, 2016
6a1023e
Temporary silence of isBoundaryCondition.
ljubobratovicrelja Oct 11, 2016
66367dc
Refactoring of bilateralFilter function.
ljubobratovicrelja Oct 11, 2016
56d1ede
Tweaks in bilateralDisparityFilter to match bilateralFilter changes.
ljubobratovicrelja Oct 11, 2016
a87f2bd
Tweaks in bilateralFilter tests to match bilateralFilter changes.
ljubobratovicrelja Oct 11, 2016
549cbab
Fixed multi-channel bilateralFilter.
ljubobratovicrelja Oct 11, 2016
539aced
Reorganized convolution templates to support lazy tensors.
ljubobratovicrelja Oct 11, 2016
13fc0b6
Adopted convolution changes in benchmark functions.
ljubobratovicrelja Oct 11, 2016
ecc4b0e
Refactoring of calcGradient, calcPartialDerivatives.
ljubobratovicrelja Oct 18, 2016
4569ffb
Refactoring of nonMaximaSuppression.
ljubobratovicrelja Oct 18, 2016
7f2f5b7
Refactored scaled and ranged to accept lazy tensors.
ljubobratovicrelja Oct 18, 2016
2cd6343
Parallelized calcPartialDerivatives, calcGradients and canny.
ljubobratovicrelja Oct 19, 2016
49a6963
Fixed docs typo.
ljubobratovicrelja Oct 19, 2016
ba7b6ac
Merge branch 'master' into optimization-patch-2
ljubobratovicrelja Nov 3, 2016
1d2b8e4
Merge branch 'master' into optimization-patch-2
ljubobratovicrelja Nov 3, 2016
b21c660
Refactoring of filterNonMaximum.
ljubobratovicrelja Nov 4, 2016
664a58f
Docs fixup.
ljubobratovicrelja Nov 4, 2016
fcd1ede
filterNonMaximum optimization.
ljubobratovicrelja Nov 4, 2016
b83ae5a
Added type check for filterNonMaximum input.
ljubobratovicrelja Nov 5, 2016
c42e8fd
Refactoring of warp/remap.
ljubobratovicrelja Nov 10, 2016
0a83b39
Added fastmath on linear interpolation.
ljubobratovicrelja Nov 10, 2016
24e8fbb
Updated function template arguments.
ljubobratovicrelja Nov 10, 2016
0c744a7
Refactoring of threshold.
ljubobratovicrelja Nov 10, 2016
7774f26
Fixed fastmath floor.
ljubobratovicrelja Nov 11, 2016
824a4a8
Merge with master.
ljubobratovicrelja Nov 11, 2016
d88c786
Docs and formatting, asserts and notes on contiguous slice request.
ljubobratovicrelja Nov 12, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 58 additions & 59 deletions source/dcv/features/corner/harris.d
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ License: $(LINK3 http://www.boost.org/LICENSE_1_0.txt, Boost Software License -
*/
module dcv.features.corner.harris;

import std.parallelism : parallel, taskPool, TaskPool;

import mir.ndslice;
import mir.ndslice.algorithm : ndEach, Yes;

import dcv.core.utils : emptySlice;
import dcv.imgproc.filter : calcPartialDerivatives;
Expand All @@ -31,12 +34,23 @@ Returns:
*/
Slice!(2, OutputType*) harrisCorners(InputType, OutputType = InputType)(Slice!(2,
InputType*) image, in uint winSize = 3, in float k = 0.64f, in float gauss = 0.84f, Slice!(2,
OutputType*) prealloc = emptySlice!(2, OutputType))
OutputType*) prealloc = emptySlice!(2, OutputType), TaskPool pool = taskPool)
in
{

HarrisDetector det;
det.k = k;
return calcCorners(image, winSize, gauss, prealloc, det);
assert(!image.empty, "Empty image given.");
assert(winSize % 2 != 0, "Kernel window size has to be odd.");
assert(gauss > 0.0, "Gaussian sigma value has to be greater than 0.");
assert(k > 0.0, "K value has to be greater than 0.");
}
body
{
if (prealloc.shape != image.shape)
{
prealloc = uninitializedSlice!OutputType(image.shape);
}
HarrisDetector detector;
detector.k = k;
return calcCorners(image, winSize, gauss, prealloc, detector, pool);
}

/**
Expand All @@ -55,10 +69,22 @@ Returns:
*/
Slice!(2, OutputType*) shiTomasiCorners(InputType, OutputType = InputType)(Slice!(2,
InputType*) image, in uint winSize = 3, in float gauss = 0.84f, Slice!(2,
OutputType*) prealloc = emptySlice!(2, OutputType))
OutputType*) prealloc = emptySlice!(2, OutputType), TaskPool pool = taskPool)
in
{
ShiTomasiDetector det;
return calcCorners(image, winSize, gauss, prealloc, det);
assert(!image.empty, "Empty image given.");
assert(winSize % 2 != 0, "Kernel window size has to be odd.");
assert(gauss > 0.0, "Gaussian sigma value has to be greater than 0.");
}
body
{
if (prealloc.shape != image.shape)
{
prealloc = uninitializedSlice!OutputType(image.shape);
}

ShiTomasiDetector detector;
return calcCorners(image, winSize, gauss, prealloc, detector, pool);
}

unittest
Expand Down Expand Up @@ -115,15 +141,15 @@ struct HarrisDetector
{
float k;

float opCall(float r1, float r2, float r3)
@nogc nothrow float opCall(float r1, float r2, float r3)
{
return (((r1 * r1) - (r2 * r3)) - k * ((r1 + r3) * r1 + r3));
}
}

struct ShiTomasiDetector
{
float opCall(float r1, float r2, float r3)
@nogc nothrow float opCall(float r1, float r2, float r3)
{
import std.math : sqrt;

Expand All @@ -132,64 +158,37 @@ struct ShiTomasiDetector
}

Slice!(2, OutputType*) calcCorners(Detector, InputType, OutputType)(Slice!(2, InputType*) image,
uint winSize, float gaussSigma, Slice!(2, OutputType*) prealloc, Detector detector)
uint winSize, float gaussSigma, Slice!(2, OutputType*) prealloc, Detector detector, TaskPool pool)
{
// TODO: implement gaussian weighting!

import std.math : exp, PI;
import std.array : uninitializedArray;
import std.range : iota;
import std.algorithm.iteration : reduce, each;
import std.algorithm.comparison : equal;
Slice!(2, InputType*) fx, fy;
calcPartialDerivatives(image, fx, fy);

assert(!image.empty);
auto windowPack = assumeSameStructure!("corners", "fx", "fy")(prealloc, fx, fy).windows(winSize, winSize);

if (!prealloc.shape[].equal(image.shape[]))
foreach (windowRow; pool.parallel(windowPack))
{
prealloc = uninitializedArray!(OutputType[])(image.shape[].reduce!"a*b").sliced(image.shape);
windowRow.ndEach!(win => calcCornersImpl(win, detector));
}
prealloc[] = cast(OutputType)0;

auto rows = image.length!0;
auto cols = image.length!1;
return prealloc;
}

Slice!(2, InputType*) fx, fy;
calcPartialDerivatives(image, fx, fy);
@nogc nothrow
void calcCornersImpl(Window, Detector)(ref Window window, ref Detector detector)
{
float r1 = 0.0f, r2 = 0.0f, r3 = 0.0f;
float winSqr = float(window.length!0);
winSqr *= winSqr;

auto winSqr = winSize ^^ 2;
auto winHalf = winSize / 2;
window.ndEach!((pack) { auto gx = pack.fx; auto gy = pack.fy; r1 += gx * gx; r2 += gx * gy; r3 += gy * gy; });
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

outer fastmath kernel


float R; // Score value
float w, gx, gy, r1, r2, r3;
float gaussMul = 1.0f / (2.0f * PI * gaussSigma);
float gaussDel = 2.0f * (gaussSigma ^^ 2);
r1 = (r1 / winSqr) * 0.5;
r2 /= winSqr;
r3 = (r3 / winSqr) * 0.5;

foreach (i; winHalf.iota(rows - winHalf))
{
foreach (j; winHalf.iota(cols - winHalf))
{
r1 = 0.;
r2 = 0.;
r3 = 0.;
for (int cr = cast(int)(i - winHalf); cr < i + winHalf; cr++)
{
for (int cc = cast(int)(j - winHalf); cc < j + winHalf; cc++)
{
w = 1.0f; //gaussMul * exp(-((cast(float)cr - i)^^2 + (cast(float)cc - j)^^2) / gaussDel);

gx = fx[cr, cc];
gy = fy[cr, cc];
r1 += w * (gx * gx);
r2 += w * (gx * gy);
r3 += w * (gy * gy);
}
}
r1 = (r1 / winSqr) * 0.5;
r2 /= winSqr;
r3 = (r3 / winSqr) * 0.5;
R = detector(r1, r2, r3);
if (R > 0)
prealloc[i, j] = cast(OutputType)R;
}
}
return prealloc;
auto r = detector(r1, r2, r3);
if (r > 0)
window[$ / 2, $ / 2].corners = r;
}
34 changes: 13 additions & 21 deletions source/dcv/features/utils.d
Original file line number Diff line number Diff line change
Expand Up @@ -49,35 +49,27 @@ return:
Dynamic array of size_t[2], as in array of 2D points, of corner reponses
which fit the given criteria.
*/
size_t[2][] extractCorners(T)(Slice!(2, T*) cornerResponse, int count = -1, T threshold = cast(T)0)@trusted pure nothrow
if (isNumeric!T)
pure nothrow auto extractCorners(T)(Slice!(2, T*) cornerResponse, int count = -1, T threshold = 0)
if (isNumeric!T)
{
import std.algorithm : sort, map, min;
import std.algorithm.sorting : sort;
import std.algorithm.iteration : map, filter;
import std.range : take;
import std.array : array;
import std.range : take, iota;

size_t[2][float] features;

if (cornerResponse.empty)
{
return null;
}

auto rows = cornerResponse.length!0;
auto cols = cornerResponse.length!1;

foreach (r; rows.iota)
{
foreach (c; cols.iota)
{
auto res = cornerResponse[r, c];
if (res > threshold)
features[res] = [r, c];
}
}

return sort!"a > b"(features.keys).take(count > 0 ? min(count, features.length) : features.length)
.map!(a => features[a]).array;
return assumeSameStructure!("indices", "value")(indexSlice(cornerResponse.shape), cornerResponse)
.byElement
.filter!(p => p.value > threshold)
.array
.sort!((a, b) => a.value > b.value)
.take(count)
.map!(p => p.indices)
.array;
}

unittest
Expand Down
Loading