| 129 | |
| 130 | template<typename T> |
| 131 | void edgeTrackingHysteresis(Param output, const Param strong, |
| 132 | const Param weak) { |
| 133 | using cl::EnqueueArgs; |
| 134 | using cl::NDRange; |
| 135 | using std::string; |
| 136 | using std::vector; |
| 137 | |
| 138 | vector<string> options = { |
| 139 | DefineKeyValue(T, dtype_traits<T>::getName()), |
| 140 | DefineKey(EDGE_TRACER), |
| 141 | DefineKeyValue(SHRD_MEM_HEIGHT, THREADS_X + 2), |
| 142 | DefineKeyValue(SHRD_MEM_WIDTH, THREADS_Y + 2), |
| 143 | DefineKeyValue(TOTAL_NUM_THREADS, THREADS_X * THREADS_Y), |
| 144 | }; |
| 145 | options.emplace_back(getTypeBuildDefinition<T>()); |
| 146 | |
| 147 | auto edgeTraceOp = |
| 148 | common::getKernel("edgeTrackKernel", {{trace_edge_cl_src}}, |
| 149 | TemplateArgs(TemplateTypename<T>()), options); |
| 150 | |
| 151 | NDRange threads(kernel::THREADS_X, kernel::THREADS_Y); |
| 152 | |
| 153 | // Launch only threads to process non-border pixels |
| 154 | int blk_x = divup(weak.info.dims[0] - 2, threads[0]); |
| 155 | int blk_y = divup(weak.info.dims[1] - 2, threads[1]); |
| 156 | |
| 157 | // launch batch * blk_x blocks along x dimension |
| 158 | NDRange global(blk_x * weak.info.dims[2] * threads[0], |
| 159 | blk_y * weak.info.dims[3] * threads[1], 1); |
| 160 | |
| 161 | initEdgeOut<T>(output, strong, weak); |
| 162 | |
| 163 | int notFinished = 1; |
| 164 | auto dContinue = memAlloc<T>(sizeof(int)); |
| 165 | |
| 166 | while (notFinished > 0) { |
| 167 | notFinished = 0; |
| 168 | edgeTraceOp.setFlag(dContinue.get(), ¬Finished); |
| 169 | edgeTraceOp(EnqueueArgs(getQueue(), global, threads), *output.data, |
| 170 | output.info, blk_x, blk_y, *dContinue); |
| 171 | CL_DEBUG_FINISH(getQueue()); |
| 172 | notFinished = edgeTraceOp.getFlag(dContinue.get()); |
| 173 | } |
| 174 | suppressLeftOver<T>(output); |
| 175 | } |
| 176 | } // namespace kernel |
| 177 | } // namespace opencl |
| 178 | } // namespace arrayfire |
nothing calls this directly
no test coverage detected