| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 5b05f1b commit 479bab0
3 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -7,21 +7,36 @@ | |||
| 7 | 7 | * http://arrayfire.com/licenses/BSD-3-Clause | |
| 8 | 8 | ********************************************************/ | |
| 9 | 9 | ||
| 10 | + #include <arith.hpp> | ||
| 10 | 11 | #include <backend.hpp> | |
| 12 | + #include <cast.hpp> | ||
| 11 | 13 | #include <common/err_common.hpp> | |
| 14 | + #include <common/indexing_helpers.hpp> | ||
| 15 | + #include <copy.hpp> | ||
| 16 | + #include <fftconvolve.hpp> | ||
| 12 | 17 | #include <handle.hpp> | |
| 18 | + #include <logic.hpp> | ||
| 19 | + #include <math.hpp> | ||
| 13 | 20 | #include <morph.hpp> | |
| 21 | + #include <unary.hpp> | ||
| 14 | 22 | #include <af/defines.h> | |
| 15 | 23 | #include <af/dim4.hpp> | |
| 16 | 24 | #include <af/image.h> | |
| 17 | 25 | ||
| 18 | 26 | using af::dim4; | |
| 27 | + using common::flip; | ||
| 28 | + using detail::arithOp; | ||
| 19 | 29 | using detail::Array; | |
| 30 | + using detail::cast; | ||
| 20 | 31 | using detail::cdouble; | |
| 21 | 32 | using detail::cfloat; | |
| 22 | 33 | using detail::createEmptyArray; | |
| 34 | + using detail::createValueArray; | ||
| 35 | + using detail::logicOp; | ||
| 36 | + using detail::scalar; | ||
| 23 | 37 | using detail::uchar; | |
| 24 | 38 | using detail::uint; | |
| 39 | + using detail::unaryOp; | ||
| 25 | 40 | using detail::ushort; | |
| 26 | 41 | ||
| 27 | 42 | template<typename T, bool isDilation> | |
@@ -32,6 +47,62 @@ static inline af_array morph(const af_array &in, const af_array &mask) { | |||
| 32 | 47 | return getHandle(out); | |
| 33 | 48 | } | |
| 34 | 49 | ||
| 50 | + template<bool isDilation> | ||
| 51 | + static inline af_array morph(const af_array &input, const af_array &mask) { | ||
| 52 | + using detail::fftconvolve; | ||
| 53 | + | ||
| 54 | + #if defined(AF_CPU) | ||
| 55 | + #if defined(USE_MKL) | ||
| 56 | + constexpr unsigned fftMethodThreshold = 11; | ||
| 57 | + #else | ||
| 58 | + constexpr unsigned fftMethodThreshold = 27; | ||
| 59 | + #endif // defined(USE_MKL) | ||
| 60 | + #elif defined(AF_CUDA) | ||
| 61 | + constexpr unsigned fftMethodThreshold = 17; | ||
| 62 | + #elif defined(AF_OPENCL) | ||
| 63 | + constexpr unsigned fftMethodThreshold = 19; | ||
| 64 | + #endif // defined(AF_CPU) | ||
| 65 | + | ||
| 66 | + const Array<float> se = castArray<float>(mask); | ||
| 67 | + const dim4 &seDims = se.dims(); | ||
| 68 | + | ||
| 69 | + if (seDims[0] <= fftMethodThreshold) { | ||
| 70 | + return morph<char, isDilation>(input, mask); | ||
| 71 | + } | ||
| 72 | + | ||
| 73 | + DIM_ASSERT(2, (seDims[0] == seDims[1])); | ||
| 74 | + | ||
| 75 | + const Array<char> in = getArray<char>(input); | ||
| 76 | + const dim4 &inDims = in.dims(); | ||
| 77 | + const auto paddedSe = | ||
| 78 | + padArrayBorders(se, | ||
| 79 | + {static_cast<dim_t>(seDims[0] % 2 == 0), | ||
| 80 | + static_cast<dim_t>(seDims[1] % 2 == 0), 0, 0}, | ||
| 81 | + {0, 0, 0, 0}, AF_PAD_ZERO); | ||
| 82 | + | ||
| 83 | + auto fftConv = fftconvolve<float, float, cfloat, false, false, 2>; | ||
| 84 | + | ||
| 85 | + if (isDilation) { | ||
| 86 | + Array<float> dft = | ||
| 87 | + fftConv(cast<float>(in), paddedSe, false, AF_BATCH_LHS); | ||
| 88 | + | ||
| 89 | + return getHandle(cast<char>(unaryOp<float, af_round_t>(dft))); | ||
| 90 | + } else { | ||
| 91 | + const Array<char> ONES = createValueArray(inDims, scalar<char>(1)); | ||
| 92 | + const Array<float> ZEROS = createValueArray(inDims, scalar<float>(0)); | ||
| 93 | + const Array<char> inv = arithOp<char, af_sub_t>(ONES, in, inDims); | ||
| 94 | + | ||
| 95 | + Array<float> dft = | ||
| 96 | + fftConv(cast<float>(inv), paddedSe, false, AF_BATCH_LHS); | ||
| 97 | + | ||
| 98 | + Array<float> rounded = unaryOp<float, af_round_t>(dft); | ||
| 99 | + Array<char> thrshd = logicOp<float, af_gt_t>(rounded, ZEROS, inDims); | ||
| 100 | + Array<char> inverted = arithOp<char, af_sub_t>(ONES, thrshd, inDims); | ||
| 101 | + | ||
| 102 | + return getHandle(inverted); | ||
| 103 | + } | ||
| 104 | + } | ||
| 105 | + | ||
| 35 | 106 | template<typename T, bool isDilation> | |
| 36 | 107 | static inline af_array morph3d(const af_array &in, const af_array &mask) { | |
| 37 | 108 | const Array<T> input = getArray<T>(in); | |
@@ -58,7 +129,7 @@ static af_err morph(af_array *out, const af_array &in, const af_array &mask) { | |||
| 58 | 129 | switch (type) { | |
| 59 | 130 | case f32: output = morph<float, isDilation>(in, mask); break; | |
| 60 | 131 | case f64: output = morph<double, isDilation>(in, mask); break; | |
| 61 | - case b8: output = morph<char, isDilation>(in, mask); break; | ||
| 132 | + case b8: output = morph<isDilation>(in, mask); break; | ||
| 62 | 133 | case s32: output = morph<int, isDilation>(in, mask); break; | |
| 63 | 134 | case u32: output = morph<uint, isDilation>(in, mask); break; | |
| 64 | 135 | case s16: output = morph<short, isDilation>(in, mask); break; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -134,7 +134,7 @@ TYPED_TEST(Morph, Erode4x4x4) { | |||
| 134 | 134 | } | |
| 135 | 135 | ||
| 136 | 136 | template<typename T, bool isDilation, bool isColor> | |
| 137 | - void morphImageTest(string pTestFile) { | ||
| 137 | + void morphImageTest(string pTestFile, dim_t seLen) { | ||
| 138 | 138 | SUPPORTED_TYPE_CHECK(T); | |
| 139 | 139 | if (noImageIOTests()) return; | |
| 140 | 140 | ||
@@ -148,23 +148,31 @@ void morphImageTest(string pTestFile) { | |||
| 148 | 148 | size_t testCount = inDims.size(); | |
| 149 | 149 | ||
| 150 | 150 | for (size_t testId = 0; testId < testCount; ++testId) { | |
| 151 | - af_array inArray = 0; | ||
| 152 | - af_array maskArray = 0; | ||
| 153 | - af_array outArray = 0; | ||
| 154 | - af_array goldArray = 0; | ||
| 155 | - dim_t nElems = 0; | ||
| 151 | + af_array _inArray = 0; | ||
| 152 | + af_array inArray = 0; | ||
| 153 | + af_array maskArray = 0; | ||
| 154 | + af_array outArray = 0; | ||
| 155 | + af_array _goldArray = 0; | ||
| 156 | + af_array goldArray = 0; | ||
| 157 | + dim_t nElems = 0; | ||
| 156 | 158 | ||
| 157 | 159 | inFiles[testId].insert(0, string(TEST_DIR "/morph/")); | |
| 158 | 160 | outFiles[testId].insert(0, string(TEST_DIR "/morph/")); | |
| 159 | 161 | ||
| 160 | - dim4 mdims(3, 3, 1, 1); | ||
| 162 | + af_dtype targetType = static_cast<af_dtype>(dtype_traits<T>::af_type); | ||
| 163 | + | ||
| 164 | + dim4 mdims(seLen, seLen, 1, 1); | ||
| 161 | 165 | ASSERT_SUCCESS(af_constant(&maskArray, 1.0, mdims.ndims(), mdims.get(), | |
| 162 | - (af_dtype)dtype_traits<T>::af_type)); | ||
| 166 | + targetType)); | ||
| 163 | 167 | ||
| 164 | 168 | ASSERT_SUCCESS( | |
| 165 | - af_load_image(&inArray, inFiles[testId].c_str(), isColor)); | ||
| 169 | + af_load_image(&_inArray, inFiles[testId].c_str(), isColor)); | ||
| 170 | + ASSERT_SUCCESS(af_cast(&inArray, _inArray, targetType)); | ||
| 171 | + | ||
| 166 | 172 | ASSERT_SUCCESS( | |
| 167 | - af_load_image(&goldArray, outFiles[testId].c_str(), isColor)); | ||
| 173 | + af_load_image(&_goldArray, outFiles[testId].c_str(), isColor)); | ||
| 174 | + ASSERT_SUCCESS(af_cast(&goldArray, _goldArray, targetType)); | ||
| 175 | + | ||
| 168 | 176 | ASSERT_SUCCESS(af_get_elements(&nElems, goldArray)); | |
| 169 | 177 | ||
| 170 | 178 | if (isDilation) | |
@@ -181,20 +189,44 @@ void morphImageTest(string pTestFile) { | |||
| 181 | 189 | ASSERT_EQ(true, compareArraysRMSD(nElems, goldData.data(), | |
| 182 | 190 | outData.data(), 0.018f)); | |
| 183 | 191 | ||
| 192 | + ASSERT_SUCCESS(af_release_array(_inArray)); | ||
| 184 | 193 | ASSERT_SUCCESS(af_release_array(inArray)); | |
| 185 | 194 | ASSERT_SUCCESS(af_release_array(maskArray)); | |
| 186 | 195 | ASSERT_SUCCESS(af_release_array(outArray)); | |
| 196 | + ASSERT_SUCCESS(af_release_array(_goldArray)); | ||
| 187 | 197 | ASSERT_SUCCESS(af_release_array(goldArray)); | |
| 188 | 198 | } | |
| 189 | 199 | } | |
| 190 | 200 | ||
| 191 | - TEST(Morph, Grayscale) { | ||
| 192 | - morphImageTest<float, true, false>(string(TEST_DIR "/morph/gray.test")); | ||
| 201 | + TEST(Morph, GrayscaleDilation3x3StructuringElement) { | ||
| 202 | + morphImageTest<float, true, false>(string(TEST_DIR "/morph/gray.test"), 3); | ||
| 203 | + } | ||
| 204 | + | ||
| 205 | + TEST(Morph, ColorImageErosion3x3StructuringElement) { | ||
| 206 | + morphImageTest<float, false, true>(string(TEST_DIR "/morph/color.test"), 3); | ||
| 207 | + } | ||
| 208 | + | ||
| 209 | + TEST(Morph, BinaryImageDilationBy33x33Kernel) { | ||
| 210 | + morphImageTest<char, true, false>( | ||
| 211 | + string(TEST_DIR "/morph/zag_dilation.test"), 33); | ||
| 212 | + } | ||
| 213 | + | ||
| 214 | + TEST(Morph, BinaryImageErosionBy33x33Kernel) { | ||
| 215 | + morphImageTest<char, false, false>( | ||
| 216 | + string(TEST_DIR "/morph/zag_erosion.test"), 33); | ||
| 217 | + } | ||
| 218 | + | ||
| 219 | + #if defined(AF_CPU) // float image 33x33 morph ops | ||
| 220 | + TEST(Morph, DilationBy33x33Kernel) { | ||
| 221 | + morphImageTest<float, true, true>( | ||
| 222 | + string(TEST_DIR "/morph/baboon_dilation.test"), 33); | ||
| 193 | 223 | } | |
| 194 | 224 | ||
| 195 | - TEST(Morph, ColorImage) { | ||
| 196 | - morphImageTest<float, false, true>(string(TEST_DIR "/morph/color.test")); | ||
| 225 | + TEST(Morph, ErosionBy33x33Kernel) { | ||
| 226 | + morphImageTest<float, false, true>( | ||
| 227 | + string(TEST_DIR "/morph/baboon_erosion.test"), 33); | ||
| 197 | 228 | } | |
| 229 | + #endif // AF_CPU float image 33x33 morph ops | ||
| 198 | 230 | ||
| 199 | 231 | template<typename T, bool isDilation> | |
| 200 | 232 | void morphInputTest(void) { | |
| Back | FazBrowse Home | New Git URL |
0 commit comments