vendor: OpenCV 5.0.0 snapshot at 755e50675d97db9b7d449d8bd6b09888646f6c6e
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
if(HAVE_CUDA)
|
||||
add_definitions(-D_HFS_CUDA_ON_)
|
||||
ocv_warnings_disable(CMAKE_CXX_FLAGS -Wundef)
|
||||
if(ENABLE_CUDA_FIRST_CLASS_LANGUAGE)
|
||||
ocv_module_include_directories(${CUDAToolkit_INCLUDE_DIRS})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(the_description "Hierarchical Feature Selection for Efficient Image Segmentation")
|
||||
ocv_define_module(hfs opencv_core opencv_imgproc OPTIONAL WRAP python)
|
||||
@@ -0,0 +1,54 @@
|
||||
## OpenCV Hierarchical Feature Selection for Efficient Image Segmentation module
|
||||
|
||||
Author and maintainers: Yujun Shi (shiyujun1016@gmail.com), Yun Liu (nk12csly@mail.nankai.edu.cn).
|
||||
|
||||
Hierachical Feature Selection (HFS) is a real-time system for image segmentation. It was originally proposed in [1]. Here is the original project website: http://mmcheng.net/zh/hfs/
|
||||
|
||||
The algorithm is executed in 3 stages. In the first stage, it obtains an over-segmented image using SLIC(simple linear iterative clustering). In the last 2 stages, it iteratively merges the over-segmented image with merging method mentioned in EGB(Efficient Graph-based Image Segmentation) and learned SVM parameters.
|
||||
|
||||
In our implementation, we wrapped these stages into one single member function of the interface class.
|
||||
|
||||
Since this module used cuda in some part of the implementation, it has to be compiled with cuda support
|
||||
|
||||
For more details about the algorithm, please refer to the original paper: [1]
|
||||
|
||||
### usage
|
||||
|
||||
c++ interface:
|
||||
|
||||
```c++
|
||||
// read a image
|
||||
Mat img = imread(image_path), res;
|
||||
int _h = img.rows, _w = img.cols;
|
||||
|
||||
// create engine
|
||||
Ptr<HfsSegment> seg = HfsSegment::create( _h, _w );
|
||||
|
||||
// perform segmentation
|
||||
// now "res" is a matrix of indices
|
||||
// change the second parameter to "True" to get a rgb image for "res"
|
||||
res = seg->performSegmentGpu(img, false);
|
||||
```
|
||||
|
||||
python interface:
|
||||
|
||||
```python
|
||||
import cv2
|
||||
import numpy as np
|
||||
|
||||
img = cv2.imread(image_path)
|
||||
|
||||
# create engine
|
||||
engine = cv2.hfs.HfsSegment_create(img.shape[0], img.shape[1])
|
||||
|
||||
# perform segmentation
|
||||
# now "res" is a matrix of indices
|
||||
# change the second parameter to "True" to get a rgb image for "res"
|
||||
res = engine.performSegmentGpu(img, False)
|
||||
```
|
||||
|
||||
|
||||
|
||||
### Reference
|
||||
|
||||
[1]: M. cheng, Y. Liu, Q. Hou, J. Bian, P. Torr, S. Hu, Z. Tu HFS: Hierarchical Feature Selection for Efficient Image Segmentation ECCV, Oct.2016.
|
||||
@@ -0,0 +1,8 @@
|
||||
@inproceedings{cheng2016hfs,
|
||||
title={HFS: Hierarchical Feature Selection for Efficient Image Segmentation},
|
||||
author={Cheng, Ming-Ming and Liu, Yun and Hou, Qibin and Bian, Jiawang and Torr, Philip and Hu, Shi-Min and Tu, Zhuowen},
|
||||
booktitle={European Conference on Computer Vision},
|
||||
pages={867--882},
|
||||
year={2016},
|
||||
organization={Springer}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
|
||||
#include "opencv2/core.hpp"
|
||||
|
||||
namespace cv { namespace hfs {
|
||||
|
||||
/** @defgroup hfs Hierarchical Feature Selection for Efficient Image Segmentation
|
||||
|
||||
The opencv hfs module contains an efficient algorithm to segment an image.
|
||||
This module is implemented based on the paper Hierarchical Feature Selection for Efficient
|
||||
Image Segmentation, ECCV 2016. The original project was developed by
|
||||
Yun Liu(https://github.com/yun-liu/hfs).
|
||||
|
||||
|
||||
Introduction to Hierarchical Feature Selection
|
||||
----------------------------------------------
|
||||
|
||||
|
||||
This algorithm is executed in 3 stages:
|
||||
|
||||
In the first stage, the algorithm uses SLIC (simple linear iterative clustering) algorithm
|
||||
to obtain the superpixel of the input image.
|
||||
|
||||
In the second stage, the algorithm view each superpixel as a node in the graph.
|
||||
It will calculate a feature vector for each edge of the graph. It then calculates a weight
|
||||
for each edge based on the feature vector and trained SVM parameters. After obtaining
|
||||
weight for each edge, it will exploit EGB (Efficient Graph-based Image Segmentation)
|
||||
algorithm to merge some nodes in the graph thus obtaining a coarser segmentation
|
||||
After these operations, a post process will be executed to merge regions that are smaller
|
||||
then a specific number of pixels into their nearby region.
|
||||
|
||||
In the third stage, the algorithm exploits the similar mechanism to further merge
|
||||
the small regions obtained in the second stage into even coarser segmentation.
|
||||
|
||||
After these three stages, we can obtain the final segmentation of the image.
|
||||
For further details about the algorithm, please refer to the original paper:
|
||||
Hierarchical Feature Selection for Efficient Image Segmentation, ECCV 2016
|
||||
|
||||
*/
|
||||
|
||||
//! @addtogroup hfs
|
||||
//! @{
|
||||
class CV_EXPORTS_W HfsSegment : public Algorithm {
|
||||
public:
|
||||
|
||||
/** @brief: set and get the parameter segEgbThresholdI.
|
||||
* This parameter is used in the second stage mentioned above.
|
||||
* It is a constant used to threshold weights of the edge when merging
|
||||
* adjacent nodes when applying EGB algorithm. The segmentation result
|
||||
* tends to have more regions remained if this value is large and vice versa.
|
||||
*/
|
||||
CV_WRAP virtual void setSegEgbThresholdI(float c) = 0;
|
||||
CV_WRAP virtual float getSegEgbThresholdI() = 0;
|
||||
|
||||
|
||||
/** @brief: set and get the parameter minRegionSizeI.
|
||||
* This parameter is used in the second stage
|
||||
* mentioned above. After the EGB segmentation, regions that have fewer
|
||||
* pixels then this parameter will be merged into it's adjacent region.
|
||||
*/
|
||||
CV_WRAP virtual void setMinRegionSizeI(int n) = 0;
|
||||
CV_WRAP virtual int getMinRegionSizeI() = 0;
|
||||
|
||||
|
||||
/** @brief: set and get the parameter segEgbThresholdII.
|
||||
* This parameter is used in the third stage
|
||||
* mentioned above. It serves the same purpose as segEgbThresholdI.
|
||||
* The segmentation result tends to have more regions remained if
|
||||
* this value is large and vice versa.
|
||||
*/
|
||||
CV_WRAP virtual void setSegEgbThresholdII(float c) = 0;
|
||||
CV_WRAP virtual float getSegEgbThresholdII() = 0;
|
||||
|
||||
|
||||
/** @brief: set and get the parameter minRegionSizeII.
|
||||
* This parameter is used in the third stage
|
||||
* mentioned above. It serves the same purpose as minRegionSizeI
|
||||
*/
|
||||
CV_WRAP virtual void setMinRegionSizeII(int n) = 0;
|
||||
CV_WRAP virtual int getMinRegionSizeII() = 0;
|
||||
|
||||
|
||||
/** @brief: set and get the parameter spatialWeight.
|
||||
* This parameter is used in the first stage
|
||||
* mentioned above(the SLIC stage). It describes how important is the role
|
||||
* of position when calculating the distance between each pixel and it's
|
||||
* center. The exact formula to calculate the distance is
|
||||
* \f$colorDistance + spatialWeight \times spatialDistance\f$.
|
||||
* The segmentation result tends to have more local consistency
|
||||
* if this value is larger.
|
||||
*/
|
||||
CV_WRAP virtual void setSpatialWeight(float w) = 0;
|
||||
CV_WRAP virtual float getSpatialWeight() = 0;
|
||||
|
||||
|
||||
/** @brief: set and get the parameter slicSpixelSize.
|
||||
* This parameter is used in the first stage mentioned
|
||||
* above(the SLIC stage). It describes the size of each
|
||||
* superpixel when initializing SLIC. Every superpixel
|
||||
* approximately has \f$slicSpixelSize \times slicSpixelSize\f$
|
||||
* pixels in the beginning.
|
||||
*/
|
||||
CV_WRAP virtual void setSlicSpixelSize(int n) = 0;
|
||||
CV_WRAP virtual int getSlicSpixelSize() = 0;
|
||||
|
||||
|
||||
/** @brief: set and get the parameter numSlicIter.
|
||||
* This parameter is used in the first stage. It
|
||||
* describes how many iteration to perform when executing SLIC.
|
||||
*/
|
||||
CV_WRAP virtual void setNumSlicIter(int n) = 0;
|
||||
CV_WRAP virtual int getNumSlicIter() = 0;
|
||||
|
||||
/** @brief do segmentation gpu
|
||||
* @param src: the input image
|
||||
* @param ifDraw: if draw the image in the returned Mat. if this parameter is false,
|
||||
* then the content of the returned Mat is a matrix of index, describing the region
|
||||
* each pixel belongs to. And it's data type is CV_16U. If this parameter is true,
|
||||
* then the returned Mat is a segmented picture, and color of each region is the
|
||||
* average color of all pixels in that region. And it's data type is the same as
|
||||
* the input image
|
||||
*/
|
||||
CV_WRAP virtual Mat performSegmentGpu(InputArray src, bool ifDraw = true) = 0;
|
||||
|
||||
/** @brief do segmentation with cpu
|
||||
* This method is only implemented for reference.
|
||||
* It is highly NOT recommanded to use it.
|
||||
*/
|
||||
CV_WRAP virtual Mat performSegmentCpu(InputArray src, bool ifDraw = true) = 0;
|
||||
|
||||
/** @brief: create a hfs object
|
||||
* @param height: the height of the input image
|
||||
* @param width: the width of the input image
|
||||
* @param segEgbThresholdI: parameter segEgbThresholdI
|
||||
* @param minRegionSizeI: parameter minRegionSizeI
|
||||
* @param segEgbThresholdII: parameter segEgbThresholdII
|
||||
* @param minRegionSizeII: parameter minRegionSizeII
|
||||
* @param spatialWeight: parameter spatialWeight
|
||||
* @param slicSpixelSize: parameter slicSpixelSize
|
||||
* @param numSlicIter: parameter numSlicIter
|
||||
*/
|
||||
CV_WRAP static Ptr<HfsSegment> create(int height, int width,
|
||||
float segEgbThresholdI = 0.08f, int minRegionSizeI = 100,
|
||||
float segEgbThresholdII = 0.28f, int minRegionSizeII = 200,
|
||||
float spatialWeight = 0.6f, int slicSpixelSize = 8, int numSlicIter = 5);
|
||||
|
||||
};
|
||||
|
||||
//! @}
|
||||
|
||||
}} // namespace cv { namespace hfs {
|
||||
@@ -0,0 +1,9 @@
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
project(example)
|
||||
find_package(OpenCV REQUIRED)
|
||||
|
||||
set(SOURCES example.cpp)
|
||||
|
||||
include_directories(${OpenCV_INCLUDE_DIRS})
|
||||
add_executable(example ${SOURCES} ${HEADERS})
|
||||
target_link_libraries(example ${OpenCV_LIBS})
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 69 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
@@ -0,0 +1,45 @@
|
||||
#include "opencv2/core.hpp"
|
||||
#include "opencv2/imgcodecs.hpp"
|
||||
#include "opencv2/hfs.hpp"
|
||||
|
||||
using namespace cv;
|
||||
using namespace cv::hfs;
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// invalid number of command line parameter
|
||||
if( argc != 2 ) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
char* path = argv[1];
|
||||
// read in a pictrue to initialize the height and width
|
||||
Mat src = imread(path), res;
|
||||
int _h = src.rows, _w = src.cols;
|
||||
|
||||
// initialize the HfsSegment object
|
||||
// In this example, we used default paramters.
|
||||
// However, bear in mind that you can pass in your
|
||||
// own parameters in with this function.
|
||||
Ptr<HfsSegment> h = HfsSegment::create( _h, _w );
|
||||
|
||||
// segment and write the first result.
|
||||
res = h->performSegmentGpu(src);
|
||||
imwrite( "segment_default_gpu.jpg", res );
|
||||
// also, there is CPU interface for that
|
||||
res = h->performSegmentCpu(src);
|
||||
imwrite( "segment_default_cpu.jpg", res );
|
||||
|
||||
// also, instead of getting a segmented image
|
||||
// from our interface, you can also choose to not to
|
||||
// draw the result on the Mat and only get a matrix
|
||||
// of index. Note that the data type of the returned
|
||||
// Mat in this case is CV_16U
|
||||
Mat idx_mat = h->performSegmentGpu( src, false );
|
||||
|
||||
// also, you can change any parameters as you want
|
||||
h->setSlicSpixelSize(10);
|
||||
res = h->performSegmentGpu(src);
|
||||
imwrite( "segment_changed_param.jpg", res );
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,325 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
|
||||
// #ifdef _HFS_CUDA_ON_
|
||||
|
||||
#include "../precomp.hpp"
|
||||
#include "../slic/slic.hpp"
|
||||
|
||||
namespace cv { namespace hfs { namespace slic { namespace engines {
|
||||
|
||||
|
||||
__global__ void cvtImgSpaceDevice(const Vector4u* inimg,
|
||||
Vector2i img_size, Vector4f* outimg);
|
||||
|
||||
__global__ void initClusterCentersDevice(const Vector4f* inimg,
|
||||
Vector2i map_size, Vector2i img_size, int spixel_size,
|
||||
gSpixelInfo* out_spixel);
|
||||
|
||||
__global__ void findCenterAssociationDevice(const Vector4f* inimg,
|
||||
const gSpixelInfo* in_spixel_map, Vector2i map_size,
|
||||
Vector2i img_size, int spixel_size, float weight,
|
||||
float max_xy_dist, float max_color_dist, int* out_idx_img);
|
||||
|
||||
__global__ void updateClusterCenterDevice(const Vector4f* inimg,
|
||||
const int* in_idx_img, Vector2i map_size, Vector2i img_size,
|
||||
int spixel_size, int no_blocks_per_line, gSpixelInfo* accum_map);
|
||||
|
||||
__global__ void finalizeReductionResultDevice(const gSpixelInfo* accum_map,
|
||||
Vector2i map_size, int no_blocks_per_spixel,
|
||||
gSpixelInfo* spixel_list);
|
||||
|
||||
__global__ void enforceConnectivityDevice(const int* in_idx_img,
|
||||
Vector2i img_size, int* out_idx_img);
|
||||
|
||||
__global__ void enforceConnectivityDevice1_2(const int* in_idx_img,
|
||||
Vector2i img_size, int* out_idx_img);
|
||||
|
||||
|
||||
|
||||
SegEngineGPU::SegEngineGPU(const slicSettings& in_settings) : SegEngine(in_settings)
|
||||
{
|
||||
source_img = Ptr<UChar4Image>(new UChar4Image(in_settings.img_size));
|
||||
cvt_img = Ptr<Float4Image>(new Float4Image(in_settings.img_size));
|
||||
idx_img = Ptr<IntImage>(new IntImage(in_settings.img_size));
|
||||
tmp_idx_img = Ptr<IntImage>(new IntImage(in_settings.img_size));
|
||||
|
||||
spixel_size = in_settings.spixel_size;
|
||||
|
||||
int spixel_per_col = (int)ceil((float)in_settings.img_size.x / (float)spixel_size);
|
||||
int spixel_per_row = (int)ceil((float)in_settings.img_size.y / (float)spixel_size);
|
||||
|
||||
map_size = Vector2i(spixel_per_col, spixel_per_row);
|
||||
spixel_map = Ptr<gSpixelMap>(new gSpixelMap(map_size));
|
||||
|
||||
no_grid_per_center =
|
||||
(int)ceil(spixel_size*3.0f / HFS_BLOCK_DIM)*((int)ceil(spixel_size*3.0f / HFS_BLOCK_DIM));
|
||||
|
||||
Vector2i accum_size(map_size.x*no_grid_per_center, map_size.y);
|
||||
accum_map = Ptr<gSpixelMap>(new gSpixelMap(accum_size));
|
||||
|
||||
// normalizing factors
|
||||
max_color_dist = 15.0f / (1.7321f * 128);
|
||||
max_color_dist *= max_color_dist;
|
||||
max_xy_dist = 1.0f / (2 * spixel_size * spixel_size);
|
||||
}
|
||||
|
||||
SegEngineGPU::~SegEngineGPU() {}
|
||||
|
||||
|
||||
void SegEngineGPU::cvtImgSpace(Ptr<UChar4Image> inimg, Ptr<Float4Image> outimg)
|
||||
{
|
||||
Vector4u* inimg_ptr = inimg->getGpuData();
|
||||
Vector4f* outimg_ptr = outimg->getGpuData();
|
||||
|
||||
dim3 blockSize(HFS_BLOCK_DIM, HFS_BLOCK_DIM);
|
||||
dim3 gridSize = getGridSize(img_size, blockSize);
|
||||
cvtImgSpaceDevice <<<gridSize, blockSize >>>(inimg_ptr, img_size, outimg_ptr);
|
||||
}
|
||||
|
||||
void SegEngineGPU::initClusterCenters()
|
||||
{
|
||||
gSpixelInfo* spixel_list = spixel_map->getGpuData();
|
||||
Vector4f* img_ptr = cvt_img->getGpuData();
|
||||
|
||||
dim3 blockSize(HFS_BLOCK_DIM, HFS_BLOCK_DIM);
|
||||
dim3 gridSize = getGridSize(map_size, blockSize);
|
||||
initClusterCentersDevice <<<gridSize, blockSize >>>
|
||||
(img_ptr, map_size, img_size, spixel_size, spixel_list);
|
||||
}
|
||||
|
||||
void SegEngineGPU::findCenterAssociation()
|
||||
{
|
||||
gSpixelInfo* spixel_list = spixel_map->getGpuData();
|
||||
Vector4f* img_ptr = cvt_img->getGpuData();
|
||||
int* idx_ptr = idx_img->getGpuData();
|
||||
|
||||
dim3 blockSize(HFS_BLOCK_DIM, HFS_BLOCK_DIM);
|
||||
dim3 gridSize = getGridSize(img_size, blockSize);
|
||||
|
||||
findCenterAssociationDevice <<<gridSize, blockSize >>>
|
||||
(img_ptr, spixel_list, map_size, img_size,
|
||||
spixel_size, slic_settings.coh_weight,
|
||||
max_xy_dist, max_color_dist, idx_ptr);
|
||||
}
|
||||
|
||||
void SegEngineGPU::updateClusterCenter()
|
||||
{
|
||||
gSpixelInfo* accum_map_ptr = accum_map->getGpuData();
|
||||
gSpixelInfo* spixel_list_ptr = spixel_map->getGpuData();
|
||||
Vector4f* img_ptr = cvt_img->getGpuData();
|
||||
int* idx_ptr = idx_img->getGpuData();
|
||||
|
||||
int no_blocks_per_line = (int)ceil(spixel_size * 3.0f / HFS_BLOCK_DIM);
|
||||
|
||||
dim3 blockSize(HFS_BLOCK_DIM, HFS_BLOCK_DIM);
|
||||
dim3 gridSize(map_size.x, map_size.y, no_grid_per_center);
|
||||
|
||||
updateClusterCenterDevice <<<gridSize, blockSize >>>
|
||||
(img_ptr, idx_ptr, map_size, img_size,
|
||||
spixel_size, no_blocks_per_line, accum_map_ptr);
|
||||
|
||||
dim3 gridSize2(map_size.x, map_size.y);
|
||||
|
||||
finalizeReductionResultDevice <<<gridSize2, blockSize >>>
|
||||
(accum_map_ptr, map_size, no_grid_per_center, spixel_list_ptr);
|
||||
}
|
||||
|
||||
void SegEngineGPU::enforceConnectivity()
|
||||
{
|
||||
int* idx_ptr = idx_img->getGpuData();
|
||||
int* tmp_idx_ptr = tmp_idx_img->getGpuData();
|
||||
|
||||
dim3 blockSize(HFS_BLOCK_DIM, HFS_BLOCK_DIM);
|
||||
dim3 gridSize = getGridSize(img_size, blockSize);
|
||||
|
||||
enforceConnectivityDevice <<<gridSize, blockSize >>>
|
||||
(idx_ptr, img_size, tmp_idx_ptr);
|
||||
enforceConnectivityDevice <<<gridSize, blockSize >>>
|
||||
(tmp_idx_ptr, img_size, idx_ptr);
|
||||
enforceConnectivityDevice1_2 <<<gridSize, blockSize >>>
|
||||
(idx_ptr, img_size, tmp_idx_ptr);
|
||||
enforceConnectivityDevice1_2 <<<gridSize, blockSize >>>
|
||||
(tmp_idx_ptr, img_size, idx_ptr);
|
||||
}
|
||||
|
||||
|
||||
__global__ void cvtImgSpaceDevice(const Vector4u* inimg, Vector2i img_size,
|
||||
Vector4f* outimg)
|
||||
{
|
||||
int idx_x = threadIdx.x + blockIdx.x * blockDim.x;
|
||||
int idx_y = threadIdx.y + blockIdx.y * blockDim.y;
|
||||
if (idx_x >= img_size.x || idx_y >= img_size.y)
|
||||
return;
|
||||
|
||||
int idx = idx_y*img_size.x + idx_x;
|
||||
rgb2CIELab(inimg[idx], outimg[idx]);
|
||||
}
|
||||
|
||||
__global__ void initClusterCentersDevice(const Vector4f* inimg,
|
||||
Vector2i map_size, Vector2i img_size, int spixel_size,
|
||||
gSpixelInfo* out_spixel)
|
||||
{
|
||||
int x = threadIdx.x + blockIdx.x * blockDim.x;
|
||||
int y = threadIdx.y + blockIdx.y * blockDim.y;
|
||||
if (x >= map_size.x || y >= map_size.y) return;
|
||||
|
||||
initClusterCentersShared(inimg, map_size,
|
||||
img_size, spixel_size, x, y, out_spixel);
|
||||
}
|
||||
|
||||
__global__ void findCenterAssociationDevice(const Vector4f* inimg,
|
||||
const gSpixelInfo* in_spixel_map, Vector2i map_size,
|
||||
Vector2i img_size, int spixel_size, float weight,
|
||||
float max_xy_dist, float max_color_dist, int* out_idx_img)
|
||||
{
|
||||
int x = threadIdx.x + blockIdx.x * blockDim.x;
|
||||
int y = threadIdx.y + blockIdx.y * blockDim.y;
|
||||
if (x >= img_size.x || y >= img_size.y) return;
|
||||
findCenterAssociationShared(inimg, in_spixel_map, map_size, img_size,
|
||||
spixel_size, weight, x, y, max_xy_dist, max_color_dist, out_idx_img);
|
||||
}
|
||||
|
||||
__global__ void updateClusterCenterDevice(const Vector4f* inimg,
|
||||
const int* in_idx_img, Vector2i map_size, Vector2i img_size,
|
||||
int spixel_size, int no_blocks_per_line, gSpixelInfo* accum_map)
|
||||
{
|
||||
int local_id = threadIdx.y * blockDim.x + threadIdx.x;
|
||||
|
||||
__shared__ Float4_ color_shared[HFS_BLOCK_DIM*HFS_BLOCK_DIM];
|
||||
__shared__ Float2_ xy_shared[HFS_BLOCK_DIM*HFS_BLOCK_DIM];
|
||||
__shared__ volatile int count_shared[HFS_BLOCK_DIM*HFS_BLOCK_DIM];
|
||||
__shared__ bool should_add;
|
||||
|
||||
color_shared[local_id] = Float4_(0, 0, 0, 0);
|
||||
xy_shared[local_id] = Float2_(0, 0);
|
||||
count_shared[local_id] = 0;
|
||||
should_add = false;
|
||||
__syncthreads();
|
||||
|
||||
int no_blocks_per_spixel = gridDim.z;
|
||||
|
||||
int spixel_id = blockIdx.y * map_size.x + blockIdx.x;
|
||||
|
||||
// compute the relative position in the search window
|
||||
int block_x = blockIdx.z % no_blocks_per_line;
|
||||
int block_y = blockIdx.z / no_blocks_per_line;
|
||||
|
||||
int x_offset = block_x * HFS_BLOCK_DIM + threadIdx.x;
|
||||
int y_offset = block_y * HFS_BLOCK_DIM + threadIdx.y;
|
||||
|
||||
if (x_offset < spixel_size * 3 && y_offset < spixel_size * 3)
|
||||
{
|
||||
// compute the start of the search window
|
||||
int x_start = blockIdx.x * spixel_size - spixel_size;
|
||||
int y_start = blockIdx.y * spixel_size - spixel_size;
|
||||
|
||||
int x_img = x_start + x_offset;
|
||||
int y_img = y_start + y_offset;
|
||||
|
||||
if (x_img >= 0 && x_img < img_size.x && y_img >= 0 && y_img < img_size.y)
|
||||
{
|
||||
int img_idx = y_img * img_size.x + x_img;
|
||||
if (in_idx_img[img_idx] == spixel_id)
|
||||
{
|
||||
color_shared[local_id] =
|
||||
Float4_(inimg[img_idx].x, inimg[img_idx].y,
|
||||
inimg[img_idx].z, inimg[img_idx].w);
|
||||
xy_shared[local_id] = Float2_(x_img, y_img);
|
||||
count_shared[local_id] = 1;
|
||||
should_add = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
__syncthreads();
|
||||
|
||||
if (should_add)
|
||||
{
|
||||
if (local_id < 128)
|
||||
{
|
||||
color_shared[local_id] += color_shared[local_id + 128];
|
||||
xy_shared[local_id] += xy_shared[local_id + 128];
|
||||
count_shared[local_id] += count_shared[local_id + 128];
|
||||
}
|
||||
__syncthreads();
|
||||
|
||||
if (local_id < 64)
|
||||
{
|
||||
color_shared[local_id] += color_shared[local_id + 64];
|
||||
xy_shared[local_id] += xy_shared[local_id + 64];
|
||||
count_shared[local_id] += count_shared[local_id + 64];
|
||||
}
|
||||
__syncthreads();
|
||||
|
||||
if (local_id < 32)
|
||||
{
|
||||
color_shared[local_id] += color_shared[local_id + 32];
|
||||
color_shared[local_id] += color_shared[local_id + 16];
|
||||
color_shared[local_id] += color_shared[local_id + 8];
|
||||
color_shared[local_id] += color_shared[local_id + 4];
|
||||
color_shared[local_id] += color_shared[local_id + 2];
|
||||
color_shared[local_id] += color_shared[local_id + 1];
|
||||
|
||||
xy_shared[local_id] += xy_shared[local_id + 32];
|
||||
xy_shared[local_id] += xy_shared[local_id + 16];
|
||||
xy_shared[local_id] += xy_shared[local_id + 8];
|
||||
xy_shared[local_id] += xy_shared[local_id + 4];
|
||||
xy_shared[local_id] += xy_shared[local_id + 2];
|
||||
xy_shared[local_id] += xy_shared[local_id + 1];
|
||||
|
||||
count_shared[local_id] += count_shared[local_id + 32];
|
||||
count_shared[local_id] += count_shared[local_id + 16];
|
||||
count_shared[local_id] += count_shared[local_id + 8];
|
||||
count_shared[local_id] += count_shared[local_id + 4];
|
||||
count_shared[local_id] += count_shared[local_id + 2];
|
||||
count_shared[local_id] += count_shared[local_id + 1];
|
||||
}
|
||||
}
|
||||
__syncthreads();
|
||||
|
||||
if (local_id == 0)
|
||||
{
|
||||
int accum_map_idx = spixel_id * no_blocks_per_spixel + blockIdx.z;
|
||||
accum_map[accum_map_idx].center = Vector2f(xy_shared[0].x, xy_shared[0].y);
|
||||
accum_map[accum_map_idx].color_info =
|
||||
Vector4f(color_shared[0].x, color_shared[0].y,
|
||||
color_shared[0].z, color_shared[0].w);
|
||||
accum_map[accum_map_idx].num_pixels = count_shared[0];
|
||||
}
|
||||
}
|
||||
|
||||
__global__ void finalizeReductionResultDevice(const gSpixelInfo* accum_map,
|
||||
Vector2i map_size, int no_blocks_per_spixel, gSpixelInfo* spixel_list)
|
||||
{
|
||||
int x = threadIdx.x + blockIdx.x * blockDim.x;
|
||||
int y = threadIdx.y + blockIdx.y * blockDim.y;
|
||||
if (x >= map_size.x || y >= map_size.y) return;
|
||||
|
||||
finalizeReductionResultShared(accum_map,
|
||||
map_size, no_blocks_per_spixel, x, y, spixel_list);
|
||||
}
|
||||
|
||||
__global__ void enforceConnectivityDevice(const int* in_idx_img,
|
||||
Vector2i img_size, int* out_idx_img)
|
||||
{
|
||||
int x = threadIdx.x + blockIdx.x * blockDim.x;
|
||||
int y = threadIdx.y + blockIdx.y * blockDim.y;
|
||||
if (x >= img_size.x || y >= img_size.y) return;
|
||||
|
||||
supressLocalLable(in_idx_img, img_size, x, y, out_idx_img);
|
||||
}
|
||||
|
||||
__global__ void enforceConnectivityDevice1_2(const int* in_idx_img,
|
||||
Vector2i img_size, int* out_idx_img)
|
||||
{
|
||||
int x = threadIdx.x + blockIdx.x * blockDim.x;
|
||||
int y = threadIdx.y + blockIdx.y * blockDim.y;
|
||||
if (x >= img_size.x || y >= img_size.y) return;
|
||||
|
||||
supressLocalLable2(in_idx_img, img_size, x, y, out_idx_img);
|
||||
}
|
||||
|
||||
}}}}
|
||||
|
||||
// #endif
|
||||
@@ -0,0 +1,236 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
|
||||
|
||||
// #if defined _HFS_CUDA_ON_
|
||||
|
||||
#include "../precomp.hpp"
|
||||
#include "../magnitude/magnitude.hpp"
|
||||
|
||||
namespace cv { namespace hfs {
|
||||
|
||||
__global__ void derrivativeXYDevice(const uchar *gray_img,
|
||||
int *delta_x, int *delta_y, int *mag, Vector2i img_size)
|
||||
{
|
||||
int x = threadIdx.x + blockIdx.x * blockDim.x;
|
||||
int y = threadIdx.y + blockIdx.y * blockDim.y;
|
||||
if (x > img_size.x - 1 || y > img_size.y - 1)
|
||||
return;
|
||||
|
||||
int idx = y*img_size.x + x;
|
||||
|
||||
if (x == 0)
|
||||
delta_x[idx] = gray_img[idx + 1] - gray_img[idx];
|
||||
else if (x == img_size.x - 1)
|
||||
delta_x[idx] = gray_img[idx] - gray_img[idx - 1];
|
||||
else
|
||||
delta_x[idx] = gray_img[idx + 1] - gray_img[idx - 1];
|
||||
|
||||
if (y == 0)
|
||||
delta_y[idx] = gray_img[idx + img_size.x] - gray_img[idx];
|
||||
else if (y == img_size.y - 1)
|
||||
delta_y[idx] = gray_img[idx] - gray_img[idx - img_size.x];
|
||||
else
|
||||
delta_y[idx] = gray_img[idx + img_size.x] - gray_img[idx - img_size.x];
|
||||
|
||||
mag[idx] = (int)(0.5 +
|
||||
sqrt((double)(delta_x[idx] * delta_x[idx] + delta_y[idx] * delta_y[idx])));
|
||||
}
|
||||
|
||||
__device__ __forceinline__ int dmin(int a, int b)
|
||||
{
|
||||
return a < b ? a : b;
|
||||
}
|
||||
|
||||
__device__ __forceinline__ int dmax(int a, int b)
|
||||
{
|
||||
return a > b ? a : b;
|
||||
}
|
||||
|
||||
__global__ void nonMaxSuppDevice(uchar *nms_mag,
|
||||
int *delta_x, int *delta_y, int *mag, Vector2i img_size)
|
||||
{
|
||||
int x = threadIdx.x + blockIdx.x * blockDim.x;
|
||||
int y = threadIdx.y + blockIdx.y * blockDim.y;
|
||||
if (x > img_size.x - 1 || y > img_size.y - 1) return;
|
||||
|
||||
int idx = y*img_size.x + x;
|
||||
|
||||
if (x == 0 || x == img_size.x - 1 || y == 0 || y == img_size.y - 1)
|
||||
{
|
||||
nms_mag[idx] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
int m00, gx, gy, z1, z2;
|
||||
double mag1, mag2, xprep, yprep;
|
||||
|
||||
m00 = mag[idx];
|
||||
if (m00 == 0)
|
||||
{
|
||||
nms_mag[idx] = 0;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
xprep = -(gx = delta_x[idx]) / ((double)m00);
|
||||
yprep = (gy = delta_y[idx]) / ((double)m00);
|
||||
}
|
||||
|
||||
if (gx >= 0)
|
||||
{
|
||||
if (gy >= 0)
|
||||
{
|
||||
if (gx >= gy)
|
||||
{
|
||||
z1 = mag[idx - 1];
|
||||
z2 = mag[idx - img_size.x - 1];
|
||||
mag1 = (m00 - z1)*xprep + (z2 - z1)*yprep;
|
||||
|
||||
z1 = mag[idx + 1];
|
||||
z2 = mag[idx + img_size.x + 1];
|
||||
mag2 = (m00 - z1)*xprep + (z2 - z1)*yprep;
|
||||
}
|
||||
else
|
||||
{
|
||||
z1 = mag[idx - img_size.x];
|
||||
z2 = mag[idx - img_size.x - 1];
|
||||
mag1 = (z1 - z2)*xprep + (z1 - m00)*yprep;
|
||||
|
||||
z1 = mag[idx + img_size.x];
|
||||
z2 = mag[idx + img_size.x + 1];
|
||||
mag2 = (z1 - z2)*xprep + (z1 - m00)*yprep;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (gx >= -gy)
|
||||
{
|
||||
z1 = mag[idx - 1];
|
||||
z2 = mag[idx + img_size.x - 1];
|
||||
mag1 = (m00 - z1)*xprep + (z1 - z2)*yprep;
|
||||
|
||||
z1 = mag[idx + 1];
|
||||
z2 = mag[idx - img_size.x + 1];
|
||||
mag2 = (m00 - z1)*xprep + (z1 - z2)*yprep;
|
||||
}
|
||||
else
|
||||
{
|
||||
z1 = mag[idx + img_size.x];
|
||||
z2 = mag[idx + img_size.x - 1];
|
||||
mag1 = (z1 - z2)*xprep + (m00 - z1)*yprep;
|
||||
|
||||
z1 = mag[idx - img_size.x];
|
||||
z2 = mag[idx - img_size.x + 1];
|
||||
mag2 = (z1 - z2)*xprep + (m00 - z1)*yprep;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (gy >= 0)
|
||||
{
|
||||
if (-gx >= gy)
|
||||
{
|
||||
z1 = mag[idx + 1];
|
||||
z2 = mag[idx - img_size.x + 1];
|
||||
mag1 = (z1 - m00)*xprep + (z2 - z1)*yprep;
|
||||
|
||||
z1 = mag[idx - 1];
|
||||
z2 = mag[idx + img_size.x - 1];
|
||||
mag2 = (z1 - m00)*xprep + (z2 - z1)*yprep;
|
||||
}
|
||||
else
|
||||
{
|
||||
z1 = mag[idx - img_size.x];
|
||||
z2 = mag[idx - img_size.x + 1];
|
||||
mag1 = (z2 - z1)*xprep + (z1 - m00)*yprep;
|
||||
|
||||
z1 = mag[idx + img_size.x];
|
||||
z2 = mag[idx + img_size.x - 1];
|
||||
mag2 = (z2 - z1)*xprep + (z1 - m00)*yprep;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (-gx > -gy)
|
||||
{
|
||||
z1 = mag[idx + 1];
|
||||
z2 = mag[idx + img_size.x + 1];
|
||||
mag1 = (z1 - m00)*xprep + (z1 - z2)*yprep;
|
||||
|
||||
z1 = mag[idx - 1];
|
||||
z2 = mag[idx - img_size.x - 1];
|
||||
mag2 = (z1 - m00)*xprep + (z1 - z2)*yprep;
|
||||
}
|
||||
else
|
||||
{
|
||||
z1 = mag[idx + img_size.x];
|
||||
z2 = mag[idx + img_size.x + 1];
|
||||
mag1 = (z2 - z1)*xprep + (m00 - z1)*yprep;
|
||||
|
||||
z1 = mag[idx - img_size.x];
|
||||
z2 = mag[idx - img_size.x - 1];
|
||||
mag2 = (z2 - z1)*xprep + (m00 - z1)*yprep;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mag1 > 0 || mag2 >= 0)
|
||||
nms_mag[idx] = 0;
|
||||
else
|
||||
nms_mag[idx] = (uchar)dmin(dmax(m00, 0), 255);
|
||||
}
|
||||
|
||||
void Magnitude::derrivativeXYGpu()
|
||||
{
|
||||
uchar *gray_ptr = gray_img->getGpuData();
|
||||
int *dx_ptr = delta_x->getGpuData();
|
||||
int *dy_ptr = delta_y->getGpuData();
|
||||
int *mag_ptr = mag->getGpuData();
|
||||
|
||||
dim3 blockSize(HFS_BLOCK_DIM, HFS_BLOCK_DIM);
|
||||
dim3 gridSize((int)ceil((float)img_size.x / (float)blockSize.x),
|
||||
(int)ceil((float)img_size.y / (float)blockSize.y));
|
||||
|
||||
derrivativeXYDevice <<<gridSize, blockSize >>>
|
||||
(gray_ptr, dx_ptr, dy_ptr, mag_ptr, img_size);
|
||||
}
|
||||
|
||||
void Magnitude::nonMaxSuppGpu()
|
||||
{
|
||||
int *dx_ptr = delta_x->getGpuData();
|
||||
int *dy_ptr = delta_y->getGpuData();
|
||||
int *mag_ptr = mag->getGpuData();
|
||||
uchar *nms_ptr = nms_mag->getGpuData();
|
||||
|
||||
dim3 blockSize(HFS_BLOCK_DIM, HFS_BLOCK_DIM);
|
||||
dim3 gridSize((int)ceil((float)img_size.x / (float)blockSize.x),
|
||||
(int)ceil((float)img_size.y / (float)blockSize.y));
|
||||
|
||||
nonMaxSuppDevice <<<gridSize, blockSize >>>
|
||||
(nms_ptr, dx_ptr, dy_ptr, mag_ptr, img_size);
|
||||
}
|
||||
|
||||
void Magnitude::processImgGpu(const Mat& bgr3u, Mat& mag1u)
|
||||
{
|
||||
Mat gray, blur1u;
|
||||
cvtColor(bgr3u, gray, COLOR_BGR2GRAY);
|
||||
GaussianBlur(gray, blur1u, Size(7, 7), 1, 1);
|
||||
|
||||
img_size.x = bgr3u.cols;
|
||||
img_size.y = bgr3u.rows;
|
||||
|
||||
loadImage(blur1u, gray_img);
|
||||
gray_img->updateDeviceFromHost();
|
||||
derrivativeXYGpu();
|
||||
nonMaxSuppGpu();
|
||||
mag1u.create(bgr3u.rows, bgr3u.cols, CV_8UC1);
|
||||
nms_mag->updateHostFromDevice();
|
||||
loadImage(nms_mag, mag1u);
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
// #endif
|
||||
@@ -0,0 +1,143 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
|
||||
|
||||
#include "precomp.hpp"
|
||||
#include "opencv2/hfs.hpp"
|
||||
#include "hfs_core.hpp"
|
||||
|
||||
namespace cv{ namespace hfs{
|
||||
|
||||
class HfsSegmentImpl CV_FINAL : public cv::hfs::HfsSegment{
|
||||
public:
|
||||
|
||||
void setSegEgbThresholdI(float c) CV_OVERRIDE
|
||||
{
|
||||
core->hfsSettings.egbThresholdI = c;
|
||||
}
|
||||
float getSegEgbThresholdI() CV_OVERRIDE {
|
||||
return core->hfsSettings.egbThresholdI;
|
||||
}
|
||||
|
||||
|
||||
void setMinRegionSizeI(int n) CV_OVERRIDE
|
||||
{
|
||||
core->hfsSettings.minRegionSizeI = n;
|
||||
}
|
||||
int getMinRegionSizeI() CV_OVERRIDE
|
||||
{
|
||||
return core->hfsSettings.minRegionSizeI;
|
||||
}
|
||||
|
||||
void setSegEgbThresholdII(float c) CV_OVERRIDE
|
||||
{
|
||||
core->hfsSettings.egbThresholdII = c;
|
||||
}
|
||||
float getSegEgbThresholdII() CV_OVERRIDE {
|
||||
return core->hfsSettings.egbThresholdII;
|
||||
}
|
||||
|
||||
|
||||
void setMinRegionSizeII(int n) CV_OVERRIDE
|
||||
{
|
||||
core->hfsSettings.minRegionSizeII = n;
|
||||
}
|
||||
int getMinRegionSizeII() CV_OVERRIDE
|
||||
{
|
||||
return core->hfsSettings.minRegionSizeII;
|
||||
}
|
||||
|
||||
void setSpatialWeight(float w) CV_OVERRIDE
|
||||
{
|
||||
core->hfsSettings.slicSettings.coh_weight = w;
|
||||
core->reconstructEngine();
|
||||
}
|
||||
float getSpatialWeight() CV_OVERRIDE
|
||||
{
|
||||
return core->hfsSettings.slicSettings.coh_weight;
|
||||
}
|
||||
|
||||
|
||||
void setSlicSpixelSize(int n) CV_OVERRIDE
|
||||
{
|
||||
core->hfsSettings.slicSettings.spixel_size = n;
|
||||
core->reconstructEngine();
|
||||
}
|
||||
int getSlicSpixelSize() CV_OVERRIDE
|
||||
{
|
||||
return core->hfsSettings.slicSettings.spixel_size;
|
||||
}
|
||||
|
||||
|
||||
void setNumSlicIter(int n) CV_OVERRIDE
|
||||
{
|
||||
core->hfsSettings.slicSettings.num_iters = n;
|
||||
core->reconstructEngine();
|
||||
}
|
||||
int getNumSlicIter() CV_OVERRIDE
|
||||
{
|
||||
return core->hfsSettings.slicSettings.num_iters;
|
||||
}
|
||||
|
||||
|
||||
HfsSegmentImpl(int height, int width,
|
||||
float segEgbThresholdI, int minRegionSizeI, float segEgbThresholdII, int minRegionSizeII,
|
||||
float spatialWeight, int spixelSize, int numIter)
|
||||
{
|
||||
core = Ptr<HfsCore>(new HfsCore(height, width,
|
||||
segEgbThresholdI, minRegionSizeI, segEgbThresholdII, minRegionSizeII,
|
||||
spatialWeight, spixelSize, numIter));
|
||||
}
|
||||
|
||||
Mat performSegmentGpu(InputArray src, bool ifDraw = true) CV_OVERRIDE;
|
||||
Mat performSegmentCpu(InputArray src, bool ifDraw = true) CV_OVERRIDE;
|
||||
private:
|
||||
Ptr<HfsCore> core;
|
||||
};
|
||||
|
||||
Mat HfsSegmentImpl::performSegmentGpu(InputArray src, bool ifDraw) {
|
||||
Mat src_ = src.getMat();
|
||||
|
||||
CV_Assert(src_.rows == core->hfsSettings.slicSettings.img_size.y);
|
||||
CV_Assert(src_.cols == core->hfsSettings.slicSettings.img_size.x);
|
||||
|
||||
Mat seg;
|
||||
int num_css = core->processImageGpu(src_, seg);
|
||||
if(ifDraw){
|
||||
Mat res;
|
||||
core->drawSegmentationRes( seg, src_, num_css, res );
|
||||
return res;
|
||||
}else{
|
||||
return seg;
|
||||
}
|
||||
}
|
||||
|
||||
Mat HfsSegmentImpl::performSegmentCpu(InputArray src, bool ifDraw) {
|
||||
Mat src_ = src.getMat();
|
||||
|
||||
CV_Assert(src_.rows == core->hfsSettings.slicSettings.img_size.y);
|
||||
CV_Assert(src_.cols == core->hfsSettings.slicSettings.img_size.x);
|
||||
|
||||
Mat seg;
|
||||
int num_css = core->processImageCpu(src_, seg);
|
||||
if (ifDraw) {
|
||||
Mat res;
|
||||
core->drawSegmentationRes(seg, src_, num_css, res);
|
||||
return res;
|
||||
}
|
||||
else {
|
||||
return seg;
|
||||
}
|
||||
}
|
||||
|
||||
Ptr<HfsSegment> HfsSegment::create(int height, int width, float segEgbThresholdI, int minRegionSizeI,
|
||||
float segEgbThresholdII, int minRegionSizeII,
|
||||
float spatialWeight, int spixelSize, int numIter)
|
||||
{
|
||||
return Ptr<HfsSegmentImpl>(new HfsSegmentImpl(height, width,
|
||||
segEgbThresholdI, minRegionSizeI, segEgbThresholdII, minRegionSizeII,
|
||||
spatialWeight, spixelSize, numIter));
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,507 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
|
||||
#include "precomp.hpp"
|
||||
#include "hfs_core.hpp"
|
||||
#include <vector>
|
||||
using namespace std;
|
||||
|
||||
namespace cv{ namespace hfs{
|
||||
|
||||
|
||||
const Point DIRECTION4[5] =
|
||||
{
|
||||
Point(-1, 0),
|
||||
Point(0, -1),
|
||||
Point(1, 0),
|
||||
Point(0, 1),
|
||||
Point(0, 0)
|
||||
};
|
||||
|
||||
const Point CIRCLE2[13] =
|
||||
{
|
||||
Point(0, 1), Point(0, 2), Point(1, 1),
|
||||
Point(1, 0), Point(2, 0), Point(1, -1),
|
||||
Point(0, -1), Point(0, -2), Point(-1, -1),
|
||||
Point(-1, 0), Point(-2, 0), Point(-1, 1),
|
||||
Point(0, 0)
|
||||
};
|
||||
|
||||
HfsCore::HfsCore(int height, int width,
|
||||
float segThresholdI, int minRegionSizeI, float segThresholdII, int minRegionSizeII,
|
||||
float spatialWeight, int spixelSize, int numIter)
|
||||
{
|
||||
hfsSettings.egbThresholdI = segThresholdI;
|
||||
hfsSettings.minRegionSizeI = minRegionSizeI;
|
||||
hfsSettings.egbThresholdII = segThresholdII;
|
||||
hfsSettings.minRegionSizeII = minRegionSizeII;
|
||||
|
||||
hfsSettings.slicSettings.img_size.y = height;
|
||||
hfsSettings.slicSettings.img_size.x = width;
|
||||
hfsSettings.slicSettings.coh_weight = spatialWeight;
|
||||
hfsSettings.slicSettings.spixel_size = spixelSize;
|
||||
hfsSettings.slicSettings.num_iters = numIter;
|
||||
constructEngine();
|
||||
|
||||
float weight1[] = { -0.0024710407f, 0.00608298f,
|
||||
0.0047505307f, 0.0051097558f, 0.00089799752f };
|
||||
float weight2[] = { -0.0040629096f, 0.010430338f,
|
||||
0.0092625152f, 0.004976281f, 0.0037279273f };
|
||||
w1.resize(sizeof(weight1) / sizeof(weight1[0]));
|
||||
w2.resize(sizeof(weight2) / sizeof(weight2[0]));
|
||||
memcpy(w1.data(), weight1, sizeof(weight1));
|
||||
memcpy(w2.data(), weight2, sizeof(weight2));
|
||||
}
|
||||
|
||||
void HfsCore::constructEngine()
|
||||
{
|
||||
mag_engine = Ptr<Magnitude>(
|
||||
new Magnitude(hfsSettings.slicSettings.img_size.y,
|
||||
hfsSettings.slicSettings.img_size.x));
|
||||
#ifdef _HFS_CUDA_ON_
|
||||
gslic_engine = Ptr<slic::engines::CoreEngine>(
|
||||
new slic::engines::CoreEngine(hfsSettings.slicSettings));
|
||||
in_img = Ptr<UChar4Image>(
|
||||
new UChar4Image(hfsSettings.slicSettings.img_size));
|
||||
out_img = Ptr<UChar4Image>(
|
||||
new UChar4Image(hfsSettings.slicSettings.img_size));
|
||||
#endif
|
||||
}
|
||||
|
||||
void HfsCore::reconstructEngine()
|
||||
{
|
||||
#ifdef _HFS_CUDA_ON_
|
||||
gslic_engine = Ptr<slic::engines::CoreEngine>(
|
||||
new slic::engines::CoreEngine(hfsSettings.slicSettings));
|
||||
#endif
|
||||
}
|
||||
|
||||
HfsCore::~HfsCore(){}
|
||||
|
||||
void HfsCore::loadImage( const Mat& inimg, Ptr<UChar4Image> outimg )
|
||||
{
|
||||
Vector4u* outimg_ptr = outimg->getCpuData();
|
||||
for ( int y = 0; y < inimg.rows; y++ )
|
||||
{
|
||||
const Vec3b *ptr = inimg.ptr<Vec3b>(y);
|
||||
for ( int x = 0; x < inimg.cols; x++ )
|
||||
{
|
||||
int idx = x + y * inimg.cols;
|
||||
outimg_ptr[idx].z = ptr[x][0];
|
||||
outimg_ptr[idx].y = ptr[x][1];
|
||||
outimg_ptr[idx].x = ptr[x][2];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Mat HfsCore::getSLICIdxCpu(const Mat& img3u, int &num_css)
|
||||
{
|
||||
const int _h = img3u.rows;
|
||||
const int _w = img3u.cols;
|
||||
const int _s = _h*_w;
|
||||
|
||||
slic::cSLIC cslic;
|
||||
vector<int> idx_img = cslic.generate_superpixels(img3u,
|
||||
hfsSettings.slicSettings.spixel_size, hfsSettings.slicSettings.coh_weight);
|
||||
|
||||
num_css = 0;
|
||||
int _max =
|
||||
(int)ceil((float)_w / 8.0f)*(int)ceil((float)_h / 8.0f);
|
||||
vector<int> indexes(_max, 0);
|
||||
for (int i = 0; i < _s; i++)
|
||||
indexes[idx_img[i]]++;
|
||||
for (int i = 0; i < _max; i++)
|
||||
indexes[i] = (indexes[i] != 0) ? num_css++ : 0;
|
||||
for (int i = 0; i < _s; i++)
|
||||
idx_img[i] = indexes[idx_img[i]];
|
||||
Mat idx_mat(_h, _w, CV_32S, idx_img.data());
|
||||
idx_mat.convertTo(idx_mat, CV_16U);
|
||||
return idx_mat;
|
||||
}
|
||||
|
||||
Vec4f HfsCore::getColorFeature( const Vec3f& in1, const Vec3f& in2 )
|
||||
{
|
||||
Vec4f feature;
|
||||
Vec3f diff = (in1 - in2);
|
||||
feature[0] = abs(diff[0]);
|
||||
feature[1] = abs(diff[1]);
|
||||
feature[2] = abs(diff[2]);
|
||||
feature[3] = getEulerDistance( in1, in2 );
|
||||
return feature;
|
||||
}
|
||||
|
||||
int HfsCore::getAvgGradientBdry( const Mat& idx_mat,
|
||||
const vector<Mat>& mag1us, int num_css, Mat& bd_num,
|
||||
vector<Mat>& gradients )
|
||||
{
|
||||
const int _h = idx_mat.rows;
|
||||
const int _w = idx_mat.cols;
|
||||
const int size = (int)mag1us.size();
|
||||
|
||||
gradients.resize(size);
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
gradients[i].create(num_css, num_css, CV_32F);
|
||||
gradients[i] = Scalar::all(0);
|
||||
}
|
||||
bd_num.create(num_css, num_css, CV_32F);
|
||||
bd_num = Scalar::all(0);
|
||||
|
||||
for (int r = 1; r < _h - 1; r++)
|
||||
for (int c = 1; c < _w - 1; c++)
|
||||
{
|
||||
ushort curr = idx_mat.at<ushort>(r, c);
|
||||
ushort pre, tmp = 0, v[4];
|
||||
Point p1(c, r), p2;
|
||||
for (int k = 0; k < 4; k++)
|
||||
{
|
||||
p2 = p1 + DIRECTION4[k];
|
||||
pre = idx_mat.at<ushort>(p2);
|
||||
if (pre != curr)
|
||||
{
|
||||
bool flag = true;
|
||||
for (int t = 0; t < tmp; t++)
|
||||
{
|
||||
if (v[t] == pre)
|
||||
flag = false;
|
||||
}
|
||||
if (flag)
|
||||
v[tmp++] = pre;
|
||||
}
|
||||
}
|
||||
|
||||
if (tmp > 0)
|
||||
{
|
||||
for (int n = 0; n < size; n++)
|
||||
{
|
||||
int u[13]; float m[13];
|
||||
for (int k = 0; k < 13; k++)
|
||||
{
|
||||
p2 = p1 + CIRCLE2[k];
|
||||
if (!(p2.x >= 0 && p2.x < _w && p2.y >= 0 && p2.y < _h))
|
||||
{
|
||||
u[k] = -1, m[k] = 0;
|
||||
continue;
|
||||
}
|
||||
u[k] = idx_mat.at<ushort>(p2);
|
||||
m[k] = mag1us[n].at<uchar>(p2);
|
||||
}
|
||||
|
||||
for (int t = 0; t < tmp; t++)
|
||||
{
|
||||
float m_max = 0;
|
||||
for (int k = 0; k < 13; k++)
|
||||
{
|
||||
if ((u[k] == curr || u[k] == v[t]) && m[k] > m_max)
|
||||
m_max = m[k];
|
||||
}
|
||||
gradients[n].at<float>(curr, v[t]) += m_max;
|
||||
gradients[n].at<float>(v[t], curr) += m_max;
|
||||
bd_num.at<float>(curr, v[t])++;
|
||||
bd_num.at<float>(v[t], curr)++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int num = 0;
|
||||
for (int r_ = 0; r_ < num_css; r_++)
|
||||
for (int c_ = 0; c_ < num_css; c_++)
|
||||
{
|
||||
if (abs(bd_num.at<float>(r_, c_)) > DOUBLE_EPS)
|
||||
{
|
||||
for (int i = 0; i < size; i++)
|
||||
gradients[i].at<float>(r_, c_) /= bd_num.at<float>(r_, c_);
|
||||
num++;
|
||||
}
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
void HfsCore::getSegmentationI( const Mat &lab3u, const Mat &mag1u,
|
||||
const Mat &idx_mat, float c, int min_size, Mat &seg, int &num_css)
|
||||
{
|
||||
const int _h = lab3u.rows;
|
||||
const int _w = lab3u.cols;
|
||||
|
||||
vector<vector<int> > adjacent(num_css), bdPixNum(num_css);
|
||||
vector<vector<float> > bdGradient(num_css);
|
||||
for (int r_ = 1; r_ < _h - 1; r_++)
|
||||
for (int c_ = 1; c_ < _w - 1; c_++)
|
||||
{
|
||||
ushort curr = idx_mat.at<ushort>(r_, c_);
|
||||
for (int k = 0; k < 4; k++)
|
||||
{
|
||||
Point p = Point(c_, r_) + DIRECTION4[k];
|
||||
ushort pre = idx_mat.at<ushort>(p);
|
||||
if (curr > pre)
|
||||
{
|
||||
float maxG = max(mag1u.at<uchar>(p), mag1u.at<uchar>(r_, c_));
|
||||
vector<int>::iterator iter =
|
||||
find(adjacent[curr].begin(), adjacent[curr].end(), pre);
|
||||
if (iter == adjacent[curr].end())
|
||||
{
|
||||
adjacent[curr].push_back(pre);
|
||||
bdGradient[curr].push_back(maxG);
|
||||
bdPixNum[curr].push_back(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
int temp = (int)(iter - adjacent[curr].begin());
|
||||
bdGradient[curr][temp] += maxG;
|
||||
bdPixNum[curr][temp] += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < (size_t)num_css; i++)
|
||||
for (size_t j = 0; j < adjacent[i].size(); j++)
|
||||
bdGradient[i][j] /= bdPixNum[i][j];
|
||||
|
||||
int num = 0;
|
||||
for (int i = 0; i < num_css; i++)
|
||||
num += (int)adjacent[i].size();
|
||||
|
||||
vector<int> numR(num_css, 0);
|
||||
vector<Vec3f> avg_color(num_css, Vec3f(0, 0, 0));
|
||||
for (int r_ = 0; r_ < _h; r_++)
|
||||
{
|
||||
const ushort *iP = idx_mat.ptr<ushort>(r_);
|
||||
const Vec3b *cP = lab3u.ptr<Vec3b>(r_);
|
||||
for (int c_ = 0; c_ < _w; c_++)
|
||||
avg_color[iP[c_]] += cP[c_], numR[iP[c_]]++;
|
||||
}
|
||||
for (int i = 0; i < num_css; i++)
|
||||
avg_color[i] /= numR[i];
|
||||
|
||||
vector<Edge> edges(num);
|
||||
int index = 0;
|
||||
for (int i = 0; i < num_css; i++)
|
||||
{
|
||||
int adjaNum = (int)adjacent[i].size();
|
||||
for (int j = 0; j < adjaNum; j++)
|
||||
{
|
||||
edges[index].a = i;
|
||||
edges[index].b = adjacent[i][j];
|
||||
Vec4f fcolor =
|
||||
getColorFeature(avg_color[i], avg_color[adjacent[i][j]]);
|
||||
|
||||
edges[index++].w =
|
||||
fcolor[0] * w1[0] + fcolor[1] * w1[1]+
|
||||
fcolor[2] * w1[2] + fcolor[3] * w1[3]+
|
||||
bdGradient[i][j] * w1[4];
|
||||
}
|
||||
}
|
||||
CV_Assert(num == index);
|
||||
|
||||
Ptr<RegionSet> regions = egb_merge(num_css, num, edges, c, numR);
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
int a = regions->find(edges[i].a);
|
||||
int b = regions->find(edges[i].b);
|
||||
if ((a != b) && ((regions->numPix(a) < min_size) || (regions->numPix(b) < min_size)))
|
||||
regions->join(a, b);
|
||||
}
|
||||
|
||||
int idx = 1; vector<int> reg2ind(num_css), indexes(num_css);
|
||||
std::memset(indexes.data(), 0, num_css*sizeof(int));
|
||||
for (int i = 0; i < num_css; i++)
|
||||
{
|
||||
int comp = regions->find(i);
|
||||
if (!indexes[comp])
|
||||
indexes[comp] = idx++;
|
||||
reg2ind[i] = indexes[comp];
|
||||
}
|
||||
CV_Assert(regions->num_sets() == idx - 1);
|
||||
seg.create(_h, _w, CV_16U);
|
||||
for (int r_ = 0; r_ < _h; r_++)
|
||||
{
|
||||
ushort *sP = seg.ptr<ushort>(r_);
|
||||
const ushort *iP = idx_mat.ptr<ushort>(r_);
|
||||
for (int c_ = 0; c_ < _w; c_++)
|
||||
sP[c_] = (ushort)reg2ind[iP[c_]];
|
||||
}
|
||||
num_css = idx;
|
||||
}
|
||||
|
||||
void HfsCore::getSegmentationII(
|
||||
const Mat &lab3u, const Mat &mag1u, const Mat &idx_mat,
|
||||
float c, int min_size, Mat &seg, int &num_css)
|
||||
{
|
||||
const int _h = lab3u.rows;
|
||||
const int _w = lab3u.cols;
|
||||
|
||||
vector<Mat> mag1us, gradients;
|
||||
Mat bd_num, texture;
|
||||
mag1us.push_back(mag1u);
|
||||
int num = getAvgGradientBdry(idx_mat, mag1us,
|
||||
num_css, bd_num, gradients);
|
||||
// const int size = (int)gradients.size();
|
||||
CV_Assert(num % 2 == 0);
|
||||
num /= 2;
|
||||
|
||||
vector<int> num_pix(num_css, 0);
|
||||
vector<Vec3f> avg_color(num_css, Vec3f(0, 0, 0));
|
||||
for (int r_ = 0; r_ < _h; r_++)
|
||||
{
|
||||
const ushort *idx_ptr = idx_mat.ptr<ushort>(r_);
|
||||
const Vec3b *clr_ptr = lab3u.ptr<Vec3b>(r_);
|
||||
for (int c_ = 0; c_ < _w; c_++)
|
||||
num_pix[idx_ptr[c_]]++, avg_color[idx_ptr[c_]] += clr_ptr[c_];
|
||||
}
|
||||
for (int i = 1; i < num_css; i++)
|
||||
avg_color[i] /= num_pix[i];
|
||||
|
||||
vector<Edge> edges(num);
|
||||
int index = 0;
|
||||
for (int r_ = 0; r_ < num_css; r_++)
|
||||
for (int c_ = 0; c_ < r_; c_++)
|
||||
{
|
||||
if (bd_num.at<int>(r_, c_) == 0) continue;
|
||||
edges[index].a = r_;
|
||||
edges[index].b = c_;
|
||||
Vec4f fcolor = getColorFeature(avg_color[r_], avg_color[c_]);
|
||||
edges[index].w =
|
||||
fcolor[0] * w2[0] + fcolor[1] * w2[1]+
|
||||
fcolor[2] * w2[2] + fcolor[3] * w2[3];
|
||||
edges[index].w += gradients[0].at<float>(r_, c_)*w2[4];
|
||||
index++;
|
||||
}
|
||||
CV_Assert(num == index);
|
||||
|
||||
Ptr<RegionSet> regions = egb_merge(num_css, num, edges, c, num_pix);
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
int a = regions->find(edges[i].a);
|
||||
int b = regions->find(edges[i].b);
|
||||
if ((a != b) && ((regions->numPix(a) < min_size)
|
||||
|| (regions->numPix(b) < min_size)))
|
||||
regions->join(a, b);
|
||||
}
|
||||
|
||||
int idx = 1;
|
||||
vector<int> reg2ind(num_css), indexes(num_css, 0);
|
||||
for (int i = 1; i < num_css; i++)
|
||||
{
|
||||
int comp = regions->find(i);
|
||||
if (!indexes[comp])
|
||||
indexes[comp] = idx++;
|
||||
reg2ind[i] = indexes[comp];
|
||||
}
|
||||
CV_Assert(regions->num_sets() == idx);
|
||||
seg.create(_h, _w, CV_16U);
|
||||
for (int r_ = 0; r_ < _h; r_++)
|
||||
{
|
||||
ushort *sP = seg.ptr<ushort>(r_);
|
||||
const ushort *iP = idx_mat.ptr<ushort>(r_);
|
||||
for (int c_ = 0; c_ < _w; c_++)
|
||||
sP[c_] = (ushort)reg2ind[iP[c_]];
|
||||
}
|
||||
|
||||
num_css = idx - 1;
|
||||
}
|
||||
|
||||
void HfsCore::drawSegmentationRes( const Mat& seg,
|
||||
const Mat& img3u, int num_css, Mat &show )
|
||||
{
|
||||
const int _h = img3u.rows;
|
||||
const int _w = img3u.cols;
|
||||
|
||||
vector<int> region_size(num_css, 0);
|
||||
vector<Vec3f> avg_color(num_css, Vec3f(0, 0, 0));
|
||||
for (int r = 0; r < _h; r++)
|
||||
{
|
||||
const Vec3b* imP = img3u.ptr<Vec3b>(r);
|
||||
const ushort* segP = seg.ptr<ushort>(r);
|
||||
for (int c = 0; c < _w; c++)
|
||||
{
|
||||
avg_color[segP[c] - 1] += imP[c];
|
||||
region_size[segP[c] - 1]++;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < num_css; i++)
|
||||
avg_color[i] /= region_size[i];
|
||||
|
||||
show.create(img3u.size(), img3u.type());
|
||||
for (int r = 0; r < _h; r++)
|
||||
{
|
||||
Vec3b *data = show.ptr<Vec3b>(r);
|
||||
const ushort* seg_ptr = seg.ptr<ushort>(r);
|
||||
for (int c = 0; c < _w; c++)
|
||||
data[c] = avg_color[seg_ptr[c] - 1];
|
||||
}
|
||||
}
|
||||
|
||||
int HfsCore::processImageCpu(const Mat &img3u, Mat &seg)
|
||||
{
|
||||
Mat idx_mat, lab3u, mag1u, tmp;
|
||||
int num_css;
|
||||
|
||||
idx_mat = getSLICIdxCpu(img3u, num_css);
|
||||
cv::cvtColor(img3u, lab3u, COLOR_BGR2Lab);
|
||||
|
||||
mag_engine->processImgCpu(img3u, mag1u);
|
||||
|
||||
getSegmentationI( lab3u, mag1u, idx_mat,
|
||||
hfsSettings.egbThresholdI, hfsSettings.minRegionSizeI, tmp, num_css );
|
||||
getSegmentationII(lab3u, mag1u, tmp,
|
||||
hfsSettings.egbThresholdII, hfsSettings.minRegionSizeII, seg, num_css);
|
||||
return num_css;
|
||||
}
|
||||
|
||||
int HfsCore::processImageGpu(const Mat &img3u, Mat &seg)
|
||||
{
|
||||
#ifdef _HFS_CUDA_ON_
|
||||
Mat idx_mat, lab3u, mag1u, tmp;
|
||||
int num_css;
|
||||
|
||||
idx_mat = getSLICIdxGpu(img3u, num_css);
|
||||
cv::cvtColor(img3u, lab3u, COLOR_BGR2Lab);
|
||||
|
||||
mag_engine->processImgGpu(img3u, mag1u);
|
||||
|
||||
getSegmentationI(lab3u, mag1u, idx_mat,
|
||||
hfsSettings.egbThresholdI, hfsSettings.minRegionSizeI, tmp, num_css);
|
||||
getSegmentationII(lab3u, mag1u, tmp,
|
||||
hfsSettings.egbThresholdII, hfsSettings.minRegionSizeII, seg, num_css);
|
||||
return num_css;
|
||||
#else
|
||||
return processImageCpu(img3u, seg);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _HFS_CUDA_ON_
|
||||
Mat HfsCore::getSLICIdxGpu(const Mat& img3u, int &num_css)
|
||||
{
|
||||
const int _h = img3u.rows;
|
||||
const int _w = img3u.cols;
|
||||
const int _s = _h*_w;
|
||||
|
||||
loadImage(img3u, in_img);
|
||||
gslic_engine->setImageSize(img3u.cols, img3u.rows);
|
||||
|
||||
gslic_engine->processFrame(in_img);
|
||||
const IntImage *idx_img = gslic_engine->getSegRes();
|
||||
int* idx_img_ptr = (int*)idx_img->getCpuData();
|
||||
|
||||
num_css = 0;
|
||||
int _max =
|
||||
(int)ceil((float)_w / 8.0f)*(int)ceil((float)_h / 8.0f);
|
||||
vector<int> indexes(_max, 0);
|
||||
for (int i = 0; i < _s; i++)
|
||||
indexes[idx_img_ptr[i]]++;
|
||||
for (int i = 0; i < _max; i++)
|
||||
indexes[i] = (indexes[i] != 0) ? num_css++ : 0;
|
||||
for (int i = 0; i < _s; i++)
|
||||
idx_img_ptr[i] = indexes[idx_img_ptr[i]];
|
||||
Mat idx_mat(_h, _w, CV_32S, idx_img_ptr);
|
||||
idx_mat.convertTo(idx_mat, CV_16U);
|
||||
return idx_mat;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,86 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
|
||||
#ifndef _OPENCV_HFS_CORE_HPP_
|
||||
#define _OPENCV_HFS_CORE_HPP_
|
||||
|
||||
#include "opencv2/core.hpp"
|
||||
|
||||
#include "magnitude/magnitude.hpp"
|
||||
#include "merge/merge.hpp"
|
||||
|
||||
#include "or_utils/or_types.hpp"
|
||||
#include "slic/slic.hpp"
|
||||
|
||||
#define DOUBLE_EPS 1E-6
|
||||
|
||||
namespace cv { namespace hfs {
|
||||
|
||||
|
||||
struct HfsSettings
|
||||
{
|
||||
float egbThresholdI;
|
||||
int minRegionSizeI;
|
||||
float egbThresholdII;
|
||||
int minRegionSizeII;
|
||||
cv::hfs::slic::slicSettings slicSettings;
|
||||
};
|
||||
|
||||
class HfsCore
|
||||
{
|
||||
public:
|
||||
HfsCore(int height, int width,
|
||||
float segThresholdI, int minRegionSizeI,
|
||||
float segThresholdII, int minRegionSizeII,
|
||||
float spatialWeight, int spixelSize, int numIter);
|
||||
~HfsCore();
|
||||
|
||||
void loadImage( const cv::Mat& inimg, Ptr<UChar4Image> outimg );
|
||||
inline float getEulerDistance( cv::Vec3f in1, cv::Vec3f in2 )
|
||||
{
|
||||
cv::Vec3f diff = in1 - in2;
|
||||
return sqrt(diff.dot(diff));
|
||||
}
|
||||
|
||||
cv::Vec4f getColorFeature( const cv::Vec3f& in1, const cv::Vec3f& in2 );
|
||||
int getAvgGradientBdry( const cv::Mat& idx_mat,
|
||||
const std::vector<cv::Mat> &mag1u, int num_css, cv::Mat &bd_num,
|
||||
std::vector<cv::Mat> &gradients );
|
||||
|
||||
void getSegmentationI( const cv::Mat& lab3u,
|
||||
const cv::Mat& mag1u, const cv::Mat& idx_mat,
|
||||
float c, int min_size, cv::Mat& seg, int& num_css);
|
||||
void getSegmentationII(
|
||||
const cv::Mat& lab3u, const cv::Mat& mag1u, const cv::Mat& idx_mat,
|
||||
float c, int min_size, cv::Mat& seg, int &num_css );
|
||||
void drawSegmentationRes( const cv::Mat& seg, const cv::Mat& img3u,
|
||||
int num_css, cv::Mat& show );
|
||||
|
||||
cv::Mat getSLICIdxCpu(const cv::Mat& img3u, int &num_css);
|
||||
int processImageCpu( const cv::Mat& img3u, cv::Mat& seg );
|
||||
int processImageGpu(const cv::Mat& img3u, cv::Mat& seg);
|
||||
|
||||
void constructEngine();
|
||||
void reconstructEngine();
|
||||
|
||||
public:
|
||||
HfsSettings hfsSettings;
|
||||
|
||||
private:
|
||||
std::vector<float> w1, w2;
|
||||
Ptr<Magnitude> mag_engine;
|
||||
|
||||
#ifdef _HFS_CUDA_ON_
|
||||
public:
|
||||
cv::Mat getSLICIdxGpu(const cv::Mat& img3u, int &num_css);
|
||||
private:
|
||||
cv::Ptr<UChar4Image> in_img, out_img;
|
||||
cv::Ptr<slic::engines::CoreEngine> gslic_engine;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,220 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
#include "../precomp.hpp"
|
||||
#include "magnitude.hpp"
|
||||
|
||||
namespace cv { namespace hfs {
|
||||
|
||||
Magnitude::Magnitude(int height, int width)
|
||||
{
|
||||
Vector2i size(height, width);
|
||||
delta_x = Ptr<IntImage>(new IntImage(size));
|
||||
delta_y = Ptr<IntImage>(new IntImage(size));
|
||||
mag = Ptr<IntImage>(new IntImage(size));
|
||||
gray_img = Ptr<UCharImage>(new UCharImage(size));
|
||||
nms_mag = Ptr<UCharImage>(new UCharImage(size));
|
||||
img_size = Vector2i(height, width);
|
||||
}
|
||||
|
||||
Magnitude::~Magnitude()
|
||||
{
|
||||
}
|
||||
|
||||
void Magnitude::loadImage(const Mat& inimg, Ptr<UCharImage> outimg)
|
||||
{
|
||||
const int _h = inimg.rows, _w = inimg.cols;
|
||||
uchar* outimg_ptr = outimg->getCpuData();
|
||||
for (int y = 0; y < _h; y++)
|
||||
{
|
||||
const uchar *ptr = inimg.ptr<uchar>(y);
|
||||
for (int x = 0; x < _w; x++)
|
||||
{
|
||||
int idx = x + y * _w;
|
||||
outimg_ptr[idx] = ptr[x];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Magnitude::loadImage(const Ptr<UCharImage> inimg, Mat& outimg)
|
||||
{
|
||||
const int _h = outimg.rows, _w = outimg.cols;
|
||||
const uchar* inimg_ptr = inimg->getCpuData();
|
||||
for (int y = 0; y < _h; y++)
|
||||
{
|
||||
uchar *ptr = outimg.ptr<uchar>(y);
|
||||
for (int x = 0; x < _w; x++)
|
||||
{
|
||||
int idx = x + y * outimg.cols;
|
||||
ptr[x] = inimg_ptr[idx];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Magnitude::derrivativeXYCpu()
|
||||
{
|
||||
uchar *gray_ptr = gray_img->getCpuData();
|
||||
int *dx_ptr = delta_x->getCpuData();
|
||||
int *dy_ptr = delta_y->getCpuData();
|
||||
int *mag_ptr = mag->getCpuData();
|
||||
|
||||
for (int y = 0; y < img_size.y; ++y) {
|
||||
for (int x = 0; x < img_size.x; ++x) {
|
||||
int idx = y * img_size.x + x;
|
||||
if (x == 0)
|
||||
dx_ptr[idx] = gray_ptr[idx + 1] - gray_ptr[idx];
|
||||
else if (x == img_size.x - 1)
|
||||
dx_ptr[idx] = gray_ptr[idx] - gray_ptr[idx - 1];
|
||||
else
|
||||
dx_ptr[idx] = gray_ptr[idx + 1] - gray_ptr[idx - 1];
|
||||
|
||||
if (y == 0)
|
||||
dy_ptr[idx] = gray_ptr[idx + img_size.x] - gray_ptr[idx];
|
||||
else if (y == img_size.y - 1)
|
||||
dy_ptr[idx] = gray_ptr[idx] - gray_ptr[idx - img_size.x];
|
||||
else
|
||||
dy_ptr[idx] = gray_ptr[idx + img_size.x] - gray_ptr[idx - img_size.x];
|
||||
|
||||
mag_ptr[idx] = (int)(0.5 + sqrt((double)(dx_ptr[idx] * dx_ptr[idx] + dy_ptr[idx] * dy_ptr[idx])));
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Magnitude::nonMaxSuppCpu()
|
||||
{
|
||||
int *dx_ptr = delta_x->getCpuData();
|
||||
int *dy_ptr = delta_y->getCpuData();
|
||||
int *mag_ptr = mag->getCpuData();
|
||||
uchar *nms_ptr = nms_mag->getCpuData();
|
||||
|
||||
for (int y = 0; y < img_size.y; ++y) {
|
||||
for (int x = 0; x < img_size.x; ++x) {
|
||||
int idx = y*img_size.x + x;
|
||||
if (x == 0 || x == img_size.x - 1 || y == 0 || y == img_size.y - 1) {
|
||||
nms_ptr[idx] = 0;
|
||||
continue;
|
||||
}
|
||||
int m00, gx, gy, z1, z2;
|
||||
double mag1, mag2, xprep, yprep;
|
||||
|
||||
m00 = mag_ptr[idx];
|
||||
if (m00 == 0) {
|
||||
nms_ptr[idx] = 0;
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
xprep = -(gx = dx_ptr[idx]) / ((double)m00);
|
||||
yprep = (gy = dy_ptr[idx]) / ((double)m00);
|
||||
}
|
||||
|
||||
if (gx >= 0) {
|
||||
if (gy >= 0) {
|
||||
if (gx >= gy) {
|
||||
z1 = mag_ptr[idx - 1];
|
||||
z2 = mag_ptr[idx - img_size.x - 1];
|
||||
mag1 = (m00 - z1)*xprep + (z2 - z1)*yprep;
|
||||
|
||||
z1 = mag_ptr[idx + 1];
|
||||
z2 = mag_ptr[idx + img_size.x + 1];
|
||||
mag2 = (m00 - z1)*xprep + (z2 - z1)*yprep;
|
||||
}
|
||||
else {
|
||||
z1 = mag_ptr[idx - img_size.x];
|
||||
z2 = mag_ptr[idx - img_size.x - 1];
|
||||
mag1 = (z1 - z2)*xprep + (z1 - m00)*yprep;
|
||||
|
||||
z1 = mag_ptr[idx + img_size.x];
|
||||
z2 = mag_ptr[idx + img_size.x + 1];
|
||||
mag2 = (z1 - z2)*xprep + (z1 - m00)*yprep;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (gx >= -gy) {
|
||||
z1 = mag_ptr[idx - 1];
|
||||
z2 = mag_ptr[idx + img_size.x - 1];
|
||||
mag1 = (m00 - z1)*xprep + (z1 - z2)*yprep;
|
||||
|
||||
z1 = mag_ptr[idx + 1];
|
||||
z2 = mag_ptr[idx - img_size.x + 1];
|
||||
mag2 = (m00 - z1)*xprep + (z1 - z2)*yprep;
|
||||
}
|
||||
else {
|
||||
z1 = mag_ptr[idx + img_size.x];
|
||||
z2 = mag_ptr[idx + img_size.x - 1];
|
||||
mag1 = (z1 - z2)*xprep + (m00 - z1)*yprep;
|
||||
|
||||
z1 = mag_ptr[idx - img_size.x];
|
||||
z2 = mag_ptr[idx - img_size.x + 1];
|
||||
mag2 = (z1 - z2)*xprep + (m00 - z1)*yprep;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (gy >= 0) {
|
||||
if (-gx >= gy) {
|
||||
z1 = mag_ptr[idx + 1];
|
||||
z2 = mag_ptr[idx - img_size.x + 1];
|
||||
mag1 = (z1 - m00)*xprep + (z2 - z1)*yprep;
|
||||
|
||||
z1 = mag_ptr[idx - 1];
|
||||
z2 = mag_ptr[idx + img_size.x - 1];
|
||||
mag2 = (z1 - m00)*xprep + (z2 - z1)*yprep;
|
||||
}
|
||||
else {
|
||||
z1 = mag_ptr[idx - img_size.x];
|
||||
z2 = mag_ptr[idx - img_size.x + 1];
|
||||
mag1 = (z2 - z1)*xprep + (z1 - m00)*yprep;
|
||||
|
||||
z1 = mag_ptr[idx + img_size.x];
|
||||
z2 = mag_ptr[idx + img_size.x - 1];
|
||||
mag2 = (z2 - z1)*xprep + (z1 - m00)*yprep;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (-gx > -gy) {
|
||||
z1 = mag_ptr[idx + 1];
|
||||
z2 = mag_ptr[idx + img_size.x + 1];
|
||||
mag1 = (z1 - m00)*xprep + (z1 - z2)*yprep;
|
||||
|
||||
z1 = mag_ptr[idx - 1];
|
||||
z2 = mag_ptr[idx - img_size.x - 1];
|
||||
mag2 = (z1 - m00)*xprep + (z1 - z2)*yprep;
|
||||
}
|
||||
else {
|
||||
z1 = mag_ptr[idx + img_size.x];
|
||||
z2 = mag_ptr[idx + img_size.x + 1];
|
||||
mag1 = (z2 - z1)*xprep + (m00 - z1)*yprep;
|
||||
|
||||
z1 = mag_ptr[idx - img_size.x];
|
||||
z2 = mag_ptr[idx - img_size.x - 1];
|
||||
mag2 = (z2 - z1)*xprep + (m00 - z1)*yprep;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mag1 > 0 || mag2 >= 0)
|
||||
nms_ptr[idx] = 0;
|
||||
else
|
||||
nms_ptr[idx] = (uchar)min(max(m00, 0), 255);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Magnitude::processImgCpu(const Mat &bgr3u, Mat &mag1u)
|
||||
{
|
||||
Mat gray, blur1u;
|
||||
cvtColor(bgr3u, gray, COLOR_BGR2GRAY);
|
||||
GaussianBlur(gray, blur1u, Size(7, 7), 1, 1);
|
||||
|
||||
img_size.x = bgr3u.cols;
|
||||
img_size.y = bgr3u.rows;
|
||||
|
||||
loadImage(blur1u, gray_img);
|
||||
derrivativeXYCpu();
|
||||
nonMaxSuppCpu();
|
||||
mag1u.create(bgr3u.rows, bgr3u.cols, CV_8UC1);
|
||||
loadImage(nms_mag, mag1u);
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,46 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
|
||||
#ifndef _OPENCV_MAGNITUDE_HPP_
|
||||
#define _OPENCV_MAGNITUDE_HPP_
|
||||
#include "../or_utils/or_types.hpp"
|
||||
#include "opencv2/core.hpp"
|
||||
|
||||
//------------------------------------------------------
|
||||
//
|
||||
// Compile time GPU Settings
|
||||
//
|
||||
//------------------------------------------------------
|
||||
#ifndef HFS_BLOCK_DIM
|
||||
#define HFS_BLOCK_DIM 16
|
||||
#endif
|
||||
|
||||
namespace cv { namespace hfs {
|
||||
|
||||
class Magnitude
|
||||
{
|
||||
cv::Ptr<IntImage> delta_x, delta_y, mag;
|
||||
cv::Ptr<UCharImage> gray_img, nms_mag;
|
||||
Vector2i img_size;
|
||||
|
||||
public:
|
||||
Magnitude(int height, int width);
|
||||
~Magnitude();
|
||||
|
||||
void loadImage(const cv::Mat& inimg, cv::Ptr<UCharImage> outimg);
|
||||
void loadImage(const cv::Ptr<UCharImage> inimg, cv::Mat& outimg);
|
||||
|
||||
void derrivativeXYCpu();
|
||||
void nonMaxSuppCpu();
|
||||
|
||||
void derrivativeXYGpu();
|
||||
void nonMaxSuppGpu();
|
||||
|
||||
void processImgCpu(const cv::Mat& bgr3u, cv::Mat& mag1u);
|
||||
void processImgGpu(const cv::Mat& bgr3u, cv::Mat& mag1u);
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,41 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
|
||||
#include "../precomp.hpp"
|
||||
#include "merge.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace cv { namespace hfs {
|
||||
|
||||
Ptr<RegionSet> egb_merge(int num_vertices, int num_edges,
|
||||
vector<Edge> &edges, float c, vector<int> size)
|
||||
{
|
||||
sort(edges.begin(), edges.end());
|
||||
|
||||
Ptr<RegionSet> regions(new RegionSet(num_vertices, size));
|
||||
|
||||
vector<float> threshold(num_vertices);
|
||||
for (int i = 0; i < num_vertices; i++)
|
||||
threshold[i] = c;
|
||||
|
||||
|
||||
for (int i = 0; i < num_edges; i++) {
|
||||
Edge *pedge = &edges[i];
|
||||
|
||||
int a = regions->find(pedge->a);
|
||||
int b = regions->find(pedge->b);
|
||||
if (a != b) {
|
||||
if ((pedge->w <= threshold[a]) &&
|
||||
(pedge->w <= threshold[b])) {
|
||||
regions->join(a, b);
|
||||
a = regions->find(a);
|
||||
threshold[a] = pedge->w + c / regions->mergedSize(a);
|
||||
}
|
||||
}
|
||||
}
|
||||
return regions;
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,96 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
|
||||
#ifndef _OPENCV_EGB_SEGMENT_HPP_
|
||||
#define _OPENCV_EGB_SEGMENT_HPP_
|
||||
|
||||
|
||||
#include <vector>
|
||||
#include <opencv2/core.hpp>
|
||||
|
||||
|
||||
namespace cv { namespace hfs {
|
||||
|
||||
struct Region
|
||||
{
|
||||
int rank;
|
||||
int p;
|
||||
int mergedSize;
|
||||
int numPix;
|
||||
};
|
||||
|
||||
class Edge
|
||||
{
|
||||
public:
|
||||
float w;
|
||||
int a, b;
|
||||
|
||||
bool operator<(const Edge &other) const
|
||||
{
|
||||
return this->w < other.w;
|
||||
}
|
||||
};
|
||||
|
||||
class RegionSet
|
||||
{
|
||||
public:
|
||||
RegionSet(int elements, std::vector<int> size)
|
||||
{
|
||||
elts = std::vector<Region>(elements);
|
||||
num = elements;
|
||||
for (int i = 0; i < elements; i++)
|
||||
{
|
||||
elts[i].rank = 0;
|
||||
elts[i].mergedSize = 1;
|
||||
elts[i].numPix = size[i];
|
||||
elts[i].p = i;
|
||||
}
|
||||
}
|
||||
|
||||
~RegionSet() {}
|
||||
|
||||
int find(int x)
|
||||
{
|
||||
int y = x;
|
||||
while (y != elts[y].p)
|
||||
y = elts[y].p;
|
||||
elts[x].p = y;
|
||||
return y;
|
||||
}
|
||||
|
||||
void join(int x, int y)
|
||||
{
|
||||
if (elts[x].rank > elts[y].rank)
|
||||
{
|
||||
elts[y].p = x;
|
||||
elts[x].mergedSize += elts[y].mergedSize;
|
||||
elts[x].numPix += elts[y].numPix;
|
||||
}
|
||||
else
|
||||
{
|
||||
elts[x].p = y;
|
||||
elts[y].mergedSize += elts[x].mergedSize;
|
||||
elts[y].numPix += elts[x].numPix;
|
||||
if (elts[x].rank == elts[y].rank)
|
||||
elts[y].rank++;
|
||||
}
|
||||
num--;
|
||||
}
|
||||
|
||||
int mergedSize(int x) const { return elts[x].mergedSize; }
|
||||
int numPix(int x) const { return elts[x].numPix; }
|
||||
|
||||
int num_sets() const { return num; }
|
||||
|
||||
private:
|
||||
std::vector<Region> elts;
|
||||
int num;
|
||||
};
|
||||
|
||||
Ptr<RegionSet> egb_merge(int num_vertices, int num_edges,
|
||||
std::vector<Edge>& edges, float c, std::vector<int> size);
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,30 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
|
||||
#ifndef _OPENCV_OR_IMAGE_HPP_
|
||||
#define _OPENCV_OR_IMAGE_HPP_
|
||||
|
||||
|
||||
#include "or_memory_block.hpp"
|
||||
namespace cv { namespace hfs { namespace orutils {
|
||||
|
||||
template <typename T>
|
||||
class Image : public MemoryBlock < T >
|
||||
{
|
||||
public:
|
||||
Vector2<int> noDims;
|
||||
|
||||
Image( Vector2<int> noDims_ )
|
||||
: MemoryBlock<T>( noDims_.x * noDims_.y )
|
||||
{
|
||||
this->noDims = noDims_;
|
||||
}
|
||||
|
||||
Image(const Image&);
|
||||
Image& operator=(const Image&);
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,134 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
|
||||
#ifndef _OPENCV_OR_MEMORY_BLOCK_HPP_
|
||||
#define _OPENCV_OR_MEMORY_BLOCK_HPP_
|
||||
|
||||
#ifdef _HFS_CUDA_ON_
|
||||
#include "opencv2/core/cuda/common.hpp"
|
||||
#endif
|
||||
|
||||
#include "stddef.h"
|
||||
|
||||
namespace cv { namespace hfs { namespace orutils {
|
||||
|
||||
template <typename T>
|
||||
class MemoryBlock
|
||||
{
|
||||
protected:
|
||||
T* data_cpu;
|
||||
|
||||
#ifdef _HFS_CUDA_ON_
|
||||
T* data_cuda;
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
||||
size_t dataSize;
|
||||
inline T* getCpuData()
|
||||
{
|
||||
return data_cpu;
|
||||
}
|
||||
|
||||
inline const T* getCpuData() const
|
||||
{
|
||||
return data_cpu;
|
||||
}
|
||||
|
||||
MemoryBlock(size_t dataSize_)
|
||||
{
|
||||
Allocate(dataSize_);
|
||||
clear();
|
||||
}
|
||||
|
||||
void clear(unsigned char defaultValue = 0)
|
||||
{
|
||||
memset(data_cpu, defaultValue, dataSize * sizeof(T));
|
||||
#ifdef _HFS_CUDA_ON_
|
||||
cudaSafeCall(cudaMemset(data_cuda,
|
||||
defaultValue, dataSize * sizeof(T)));
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _HFS_CUDA_ON_
|
||||
enum MemoryCopyDirection
|
||||
{
|
||||
CPU_TO_CPU, CPU_TO_CUDA, CUDA_TO_CPU, CUDA_TO_CUDA
|
||||
};
|
||||
inline const T* getGpuData() const
|
||||
{
|
||||
return data_cuda;
|
||||
}
|
||||
|
||||
inline T* getGpuData()
|
||||
{
|
||||
return data_cuda;
|
||||
}
|
||||
void updateDeviceFromHost()
|
||||
{
|
||||
cudaSafeCall(cudaMemcpy(data_cuda,
|
||||
data_cpu, dataSize * sizeof(T), cudaMemcpyHostToDevice));
|
||||
}
|
||||
void updateHostFromDevice()
|
||||
{
|
||||
cudaSafeCall(cudaMemcpy(data_cpu,
|
||||
data_cuda, dataSize * sizeof(T), cudaMemcpyDeviceToHost));
|
||||
}
|
||||
void setFrom(const MemoryBlock<T> *source,
|
||||
MemoryCopyDirection memoryCopyDirection)
|
||||
{
|
||||
switch (memoryCopyDirection)
|
||||
{
|
||||
case CPU_TO_CPU:
|
||||
memcpy(this->data_cpu, source->data_cpu,
|
||||
source->dataSize * sizeof(T));
|
||||
break;
|
||||
case CPU_TO_CUDA:
|
||||
cudaSafeCall(cudaMemcpyAsync(this->data_cuda, source->data_cpu,
|
||||
source->dataSize * sizeof(T), cudaMemcpyHostToDevice));
|
||||
break;
|
||||
case CUDA_TO_CPU:
|
||||
cudaSafeCall(cudaMemcpy(this->data_cpu, source->data_cuda,
|
||||
source->dataSize * sizeof(T), cudaMemcpyDeviceToHost));
|
||||
break;
|
||||
case CUDA_TO_CUDA:
|
||||
cudaSafeCall(cudaMemcpyAsync(this->data_cuda, source->data_cuda,
|
||||
source->dataSize * sizeof(T), cudaMemcpyDeviceToDevice));
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
virtual ~MemoryBlock() { this->Free(); }
|
||||
|
||||
void Allocate(size_t dataSize_)
|
||||
{
|
||||
//Free();
|
||||
this->dataSize = dataSize_;
|
||||
#ifdef _HFS_CUDA_ON_
|
||||
cudaSafeCall(cudaMallocHost((void**)&data_cpu, dataSize_ * sizeof(T)));
|
||||
cudaSafeCall(cudaMalloc((void**)&data_cuda, dataSize_ * sizeof(T)));
|
||||
#else
|
||||
data_cpu = new T[dataSize_];
|
||||
#endif
|
||||
}
|
||||
|
||||
void Free() {
|
||||
#ifdef _HFS_CUDA_ON_
|
||||
cudaSafeCall(cudaFreeHost(data_cpu));
|
||||
cudaSafeCall(cudaFree(data_cuda));
|
||||
#else
|
||||
delete[] data_cpu;
|
||||
#endif
|
||||
}
|
||||
|
||||
MemoryBlock(const MemoryBlock&);
|
||||
MemoryBlock& operator=(const MemoryBlock&);
|
||||
};
|
||||
|
||||
|
||||
}}}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,36 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
|
||||
#ifndef _OPENCV_OR_TYPES_HPP_
|
||||
#define _OPENCV_OR_TYPES_HPP_
|
||||
|
||||
#include "or_vector.hpp"
|
||||
#include "or_image.hpp"
|
||||
|
||||
//------------------------------------------------------
|
||||
//
|
||||
// math defines
|
||||
//
|
||||
//------------------------------------------------------
|
||||
|
||||
typedef cv::hfs::orutils::Vector2<int> Vector2i;
|
||||
typedef cv::hfs::orutils::Vector2<float> Vector2f;
|
||||
|
||||
typedef cv::hfs::orutils::Vector4<float> Vector4f;
|
||||
typedef cv::hfs::orutils::Vector4<int> Vector4i;
|
||||
typedef cv::hfs::orutils::Vector4<unsigned char> Vector4u;
|
||||
|
||||
//------------------------------------------------------
|
||||
//
|
||||
// image defines
|
||||
//
|
||||
//------------------------------------------------------
|
||||
|
||||
typedef cv::hfs::orutils::Image<int> IntImage;
|
||||
typedef cv::hfs::orutils::Image<unsigned char> UCharImage;
|
||||
typedef cv::hfs::orutils::Image<float> FloatImage;
|
||||
typedef cv::hfs::orutils::Image<Vector4f> Float4Image;
|
||||
typedef cv::hfs::orutils::Image<Vector4u> UChar4Image;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,99 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
|
||||
#ifndef _OPENCV_OR_VECTOR_HPP_
|
||||
#define _OPENCV_OR_VECTOR_HPP_
|
||||
|
||||
#ifdef __CUDACC__
|
||||
#define __CV_CUDA_HOST_DEVICE__ __host__ __device__ __forceinline__
|
||||
#else
|
||||
#define __CV_CUDA_HOST_DEVICE__
|
||||
#endif
|
||||
|
||||
namespace cv { namespace hfs { namespace orutils {
|
||||
|
||||
|
||||
template <class T>
|
||||
struct Vector2_ {
|
||||
T x, y;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct Vector4_ {
|
||||
T x, y, z, w;
|
||||
};
|
||||
|
||||
template <class T> class Vector2 : public Vector2_ < T >
|
||||
{
|
||||
public:
|
||||
__CV_CUDA_HOST_DEVICE__ Vector2() {}
|
||||
|
||||
__CV_CUDA_HOST_DEVICE__ Vector2(const T v0, const T v1)
|
||||
{
|
||||
this->x = v0;
|
||||
this->y = v1;
|
||||
}
|
||||
|
||||
__CV_CUDA_HOST_DEVICE__ Vector2(const Vector2_<T> &v)
|
||||
{
|
||||
this->x = v.x;
|
||||
this->y = v.y;
|
||||
}
|
||||
|
||||
__CV_CUDA_HOST_DEVICE__ friend Vector2<T> &operator /= (Vector2<T> &lhs, T d)
|
||||
{
|
||||
if (d == 0) {
|
||||
return lhs;
|
||||
}
|
||||
lhs.x /= d;
|
||||
lhs.y /= d;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
__CV_CUDA_HOST_DEVICE__ friend Vector2<T>&
|
||||
operator += (Vector2<T> &lhs, const Vector2<T> &rhs)
|
||||
{
|
||||
lhs.x += rhs.x;
|
||||
lhs.y += rhs.y;
|
||||
return lhs;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T> class Vector4 : public Vector4_ < T >
|
||||
{
|
||||
public:
|
||||
__CV_CUDA_HOST_DEVICE__ Vector4() {}
|
||||
|
||||
__CV_CUDA_HOST_DEVICE__ Vector4(const T v0, const T v1, const T v2, const T v3)
|
||||
{
|
||||
this->x = v0;
|
||||
this->y = v1;
|
||||
this->z = v2;
|
||||
this->w = v3;
|
||||
}
|
||||
|
||||
__CV_CUDA_HOST_DEVICE__ friend Vector4<T> &operator /= (Vector4<T> &lhs, T d)
|
||||
{
|
||||
lhs.x /= d;
|
||||
lhs.y /= d;
|
||||
lhs.z /= d;
|
||||
lhs.w /= d;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
__CV_CUDA_HOST_DEVICE__ friend Vector4<T>&
|
||||
operator += (Vector4<T> &lhs, const Vector4<T> &rhs)
|
||||
{
|
||||
lhs.x += rhs.x;
|
||||
lhs.y += rhs.y;
|
||||
lhs.z += rhs.z;
|
||||
lhs.w += rhs.w;
|
||||
return lhs;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,14 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
|
||||
#ifndef _OPENCV_PRECOMP_HPP_
|
||||
#define _OPENCV_PRECOMP_HPP_
|
||||
|
||||
#include "opencv2/core.hpp"
|
||||
#include "opencv2/imgproc.hpp"
|
||||
#include <vector>
|
||||
#include "math.h"
|
||||
#include "or_utils/or_types.hpp"
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,63 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
|
||||
#include "../precomp.hpp"
|
||||
#ifdef _HFS_CUDA_ON_
|
||||
|
||||
#include "slic.hpp"
|
||||
|
||||
namespace cv { namespace hfs { namespace slic { namespace engines {
|
||||
|
||||
SegEngine::SegEngine(const slicSettings& in_settings)
|
||||
{
|
||||
slic_settings = in_settings;
|
||||
}
|
||||
|
||||
SegEngine::~SegEngine() {}
|
||||
|
||||
void SegEngine::performSegmentation(Ptr<UChar4Image> in_img)
|
||||
{
|
||||
source_img->setFrom(in_img, UChar4Image::CPU_TO_CUDA);
|
||||
cvtImgSpace(source_img, cvt_img);
|
||||
|
||||
initClusterCenters();
|
||||
findCenterAssociation();
|
||||
|
||||
for (int i = 0; i < slic_settings.num_iters; i++)
|
||||
{
|
||||
updateClusterCenter();
|
||||
findCenterAssociation();
|
||||
}
|
||||
|
||||
enforceConnectivity();
|
||||
cudaDeviceSynchronize();
|
||||
}
|
||||
|
||||
|
||||
CoreEngine::CoreEngine(const slicSettings& in_settings)
|
||||
{
|
||||
slic_seg_engine = Ptr<SegEngine>(new SegEngineGPU(in_settings));
|
||||
}
|
||||
|
||||
CoreEngine::~CoreEngine() {}
|
||||
|
||||
void CoreEngine::setImageSize(int x, int y)
|
||||
{
|
||||
slic_seg_engine->setImageSize(x, y);
|
||||
}
|
||||
|
||||
void CoreEngine::processFrame(Ptr<UChar4Image> in_img)
|
||||
{
|
||||
slic_seg_engine->performSegmentation(in_img);
|
||||
}
|
||||
|
||||
const Ptr<IntImage> CoreEngine::getSegRes()
|
||||
{
|
||||
return slic_seg_engine->getSegMask();
|
||||
}
|
||||
|
||||
|
||||
}}}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,220 @@
|
||||
#include "../precomp.hpp"
|
||||
#include "slic.hpp"
|
||||
using namespace std;
|
||||
|
||||
#define vec2db vector<vector<bool> >
|
||||
|
||||
namespace cv{ namespace hfs{ namespace slic{
|
||||
|
||||
void cSLIC::init_data(Mat image_) {
|
||||
image = image_;
|
||||
lab = cvt_img_space();
|
||||
map_size[0] = (int)ceil((float)lab.cols / (float)spixel_size);
|
||||
map_size[1] = (int)ceil((float)lab.rows / (float)spixel_size);
|
||||
|
||||
// initialize distance normalizer
|
||||
// normalizing factors
|
||||
max_color_dist = 15.0f / (1.7321f * 128);
|
||||
max_color_dist *= max_color_dist;
|
||||
max_xy_dist = 1.0f / (2.0f * spixel_size * spixel_size);
|
||||
// initialize index map
|
||||
idx_img = vector<int>(lab.rows * lab.cols);
|
||||
for (int i = 0; i < lab.rows * lab.cols; ++i) {
|
||||
idx_img[i] = -1;
|
||||
}
|
||||
// initialize super pixel list
|
||||
spixel_list = vector<cSpixelInfo>(map_size[0] * map_size[1]);
|
||||
|
||||
// initialize cluster
|
||||
for (int x = 0; x < map_size[0]; ++x) {
|
||||
for (int y = 0; y < map_size[1]; ++y) {
|
||||
int cluster_idx = y * map_size[0] + x;
|
||||
|
||||
int img_x = x * spixel_size + spixel_size / 2;
|
||||
int img_y = y * spixel_size + spixel_size / 2;
|
||||
|
||||
img_x = img_x >= lab.cols ? (x * spixel_size + lab.cols) / 2 : img_x;
|
||||
img_y = img_y >= lab.rows ? (y * spixel_size + lab.rows) / 2 : img_y;
|
||||
|
||||
spixel_list[cluster_idx].id = cluster_idx;
|
||||
spixel_list[cluster_idx].center = Vec2f((float)img_x, (float) img_y);
|
||||
|
||||
spixel_list[cluster_idx].color_info = lab.at<Vec3f>(img_y, img_x);
|
||||
spixel_list[cluster_idx].num_pixels = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Mat cSLIC::cvt_img_space() {
|
||||
float epsilon = 0.008856f; //actual CIE standard
|
||||
float kappa = 903.3f; //actual CIE standard
|
||||
|
||||
float Xr = 0.950456f; //reference white
|
||||
float Yr = 1.0f; //reference white
|
||||
float Zr = 1.088754f; //reference white
|
||||
|
||||
Mat lab_ = Mat(image.size(), CV_32FC3);
|
||||
|
||||
for(int i = 0; i < image.rows; ++i) {
|
||||
for(int j = 0; j < image.cols; ++j){
|
||||
Vec3b pix_in = image.at<Vec3b>(i,j);
|
||||
float _r = (float)pix_in[0] / 255;
|
||||
float _g = (float)pix_in[1] / 255;
|
||||
float _b = (float)pix_in[2] / 255;
|
||||
|
||||
if (_b <= 0.04045f) _b = _b / 12.92f;
|
||||
else _b = pow((_b + 0.055f) / 1.055f, 2.4f);
|
||||
if (_g <= 0.04045f) _g = _g / 12.92f;
|
||||
else _g = pow((_g + 0.055f) / 1.055f, 2.4f);
|
||||
if (_r <= 0.04045f) _r = _r / 12.92f;
|
||||
else _r = pow((_r + 0.055f) / 1.055f, 2.4f);
|
||||
|
||||
float x = _r*0.4124564f + _g*0.3575761f + _b*0.1804375f;
|
||||
float y = _r*0.2126729f + _g*0.7151522f + _b*0.0721750f;
|
||||
float z = _r*0.0193339f + _g*0.1191920f + _b*0.9503041f;
|
||||
|
||||
|
||||
float xr = x / Xr;
|
||||
float yr = y / Yr;
|
||||
float zr = z / Zr;
|
||||
|
||||
float fx, fy, fz;
|
||||
if (xr > epsilon) fx = pow(xr, 1.0f / 3.0f);
|
||||
else fx = (kappa*xr + 16.0f) / 116.0f;
|
||||
if (yr > epsilon) fy = pow(yr, 1.0f / 3.0f);
|
||||
else fy = (kappa*yr + 16.0f) / 116.0f;
|
||||
if (zr > epsilon) fz = pow(zr, 1.0f / 3.0f);
|
||||
else fz = (kappa*zr + 16.0f) / 116.0f;
|
||||
|
||||
lab_.at<Vec3f>(i, j)[0] = 116.0f*fy - 16.0f;
|
||||
lab_.at<Vec3f>(i, j)[1] = 500.0f*(fx - fy);
|
||||
lab_.at<Vec3f>(i, j)[2] = 200.0f*(fy - fz);
|
||||
}
|
||||
}
|
||||
|
||||
return lab_;
|
||||
}
|
||||
|
||||
float cSLIC::compute_dist(Point pix, cSpixelInfo center_info) {
|
||||
Vec3f color = lab.at<Vec3f>(pix.y, pix.x);
|
||||
float dcolor =
|
||||
(color[0] - center_info.color_info[0])*(color[0] - center_info.color_info[0])
|
||||
+ (color[1] - center_info.color_info[1])*(color[1] - center_info.color_info[1])
|
||||
+ (color[2] - center_info.color_info[2])*(color[2] - center_info.color_info[2]);
|
||||
|
||||
float dxy =
|
||||
(float)((pix.x - center_info.center[0]) * (pix.x - center_info.center[0])
|
||||
+ (pix.y - center_info.center[1]) * (pix.y - center_info.center[1]));
|
||||
|
||||
float retval =
|
||||
dcolor * max_color_dist + spatial_weight * dxy * max_xy_dist;
|
||||
return sqrtf(retval);
|
||||
}
|
||||
|
||||
vector<int> cSLIC::generate_superpixels(Mat image_, int spixel_size_, float spatial_weight_) {
|
||||
spixel_size = spixel_size_;
|
||||
spatial_weight = spatial_weight_;
|
||||
|
||||
init_data(image_);
|
||||
find_association();
|
||||
for (int iter = 0; iter < 5; ++iter) {
|
||||
update_cluster_center();
|
||||
find_association();
|
||||
}
|
||||
enforce_connect(2, 16);
|
||||
enforce_connect(2, 16);
|
||||
enforce_connect(1, 5);
|
||||
enforce_connect(1, 5);
|
||||
return idx_img;
|
||||
}
|
||||
|
||||
void cSLIC::find_association() {
|
||||
for (int y = 0; y < lab.rows; ++y) {
|
||||
for (int x = 0; x < lab.cols; ++x) {
|
||||
|
||||
int ctr_x = x / spixel_size;
|
||||
int ctr_y = y / spixel_size;
|
||||
|
||||
int idx = y * lab.cols + x;
|
||||
|
||||
int minidx = -1;
|
||||
float dist = FLT_MAX;
|
||||
|
||||
for (int i = -1; i <= 1; ++i) {
|
||||
for (int j = -1; j <= 1; ++j) {
|
||||
int ctr_x_check = ctr_x + j;
|
||||
int ctr_y_check = ctr_y + i;
|
||||
if (ctr_x_check >= 0 && ctr_y_check >= 0 &&
|
||||
ctr_x_check < map_size[0] && ctr_y_check < map_size[1]) {
|
||||
int ctr_idx = ctr_y_check*map_size[0] + ctr_x_check;
|
||||
float cdist = compute_dist(Point(x, y), spixel_list[ctr_idx]);
|
||||
if (cdist < dist) {
|
||||
dist = cdist;
|
||||
minidx = spixel_list[ctr_idx].id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (minidx >= 0) {
|
||||
idx_img[idx] = minidx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cSLIC::update_cluster_center() {
|
||||
|
||||
for (int i = 0; i < map_size[0] * map_size[1]; ++i) {
|
||||
spixel_list[i].center = Vec2f(0.0f, 0.0f);
|
||||
spixel_list[i].color_info = Vec3f(0.0f, 0.0f, 0.0f);
|
||||
spixel_list[i].num_pixels = 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < lab.rows; ++i) {
|
||||
for (int j = 0; j < lab.cols; ++j) {
|
||||
int idx = i * lab.cols + j;
|
||||
spixel_list[idx_img[idx]].center += Vec2f((float)j, (float)i);
|
||||
spixel_list[idx_img[idx]].color_info += lab.at<Vec3f>(i, j);
|
||||
spixel_list[idx_img[idx]].num_pixels += 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < map_size[0] * map_size[1]; ++i) {
|
||||
if (spixel_list[i].num_pixels != 0) {
|
||||
spixel_list[i].center /= spixel_list[i].num_pixels;
|
||||
spixel_list[i].color_info /= spixel_list[i].num_pixels;
|
||||
}
|
||||
else {
|
||||
spixel_list[i].center = Vec2f(-100.0f, -100.0f);
|
||||
spixel_list[i].color_info = Vec3f(-100.0f, -100.0f, -100.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cSLIC::enforce_connect(int padding, int diff_threshold) {
|
||||
vector<int> idx_img_cpy = idx_img;
|
||||
for (int r = 0; r < lab.rows; ++r) {
|
||||
for (int c = 0; c < lab.cols; ++c) {
|
||||
if (r < padding || r >= lab.rows - padding || c < padding || c >= lab.cols - padding) {
|
||||
continue;
|
||||
}
|
||||
int idx = r*lab.cols + c;
|
||||
int num_diff = 0;
|
||||
int diff_label = -1;
|
||||
for (int i = -padding; i <= padding; ++i) {
|
||||
for (int j = -padding; j <= padding; ++j) {
|
||||
int idx_t = (r + i)*lab.cols + (c + j);
|
||||
if (idx_img_cpy[idx] != idx_img_cpy[idx_t]) {
|
||||
++num_diff;
|
||||
diff_label = idx_img_cpy[idx_t];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (num_diff > diff_threshold) {
|
||||
idx_img[idx] = diff_label;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}}}
|
||||
@@ -0,0 +1,436 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
|
||||
#ifndef _OPENCV_SLIC_HPP_
|
||||
#define _OPENCV_SLIC_HPP_
|
||||
|
||||
#include "../or_utils/or_types.hpp"
|
||||
#include "opencv2/core.hpp"
|
||||
//------------------------------------------------------
|
||||
//
|
||||
// Compile time GPU Settings
|
||||
//
|
||||
//------------------------------------------------------
|
||||
|
||||
#ifndef HFS_BLOCK_DIM
|
||||
#define HFS_BLOCK_DIM 16
|
||||
#endif
|
||||
|
||||
namespace cv { namespace hfs { namespace slic {
|
||||
|
||||
struct slicSettings
|
||||
{
|
||||
Vector2i img_size;
|
||||
int spixel_size;
|
||||
int num_iters;
|
||||
float coh_weight;
|
||||
};
|
||||
|
||||
struct cSpixelInfo
|
||||
{
|
||||
Vec2f center;
|
||||
Vec3f color_info;
|
||||
int id;
|
||||
int num_pixels;
|
||||
};
|
||||
|
||||
class cSLIC {
|
||||
private:
|
||||
cv::Mat image;
|
||||
cv::Mat lab;
|
||||
std::vector<int> idx_img;
|
||||
|
||||
cv::Vec2i map_size;
|
||||
std::vector<cSpixelInfo> spixel_list;
|
||||
int spixel_size;
|
||||
float spatial_weight;
|
||||
float max_xy_dist, max_color_dist;
|
||||
|
||||
float compute_dist(cv::Point pix, cSpixelInfo center_info);
|
||||
|
||||
void init_data(cv::Mat image_);
|
||||
cv::Mat cvt_img_space();
|
||||
void find_association();
|
||||
void update_cluster_center();
|
||||
void enforce_connect(int padding, int diff_threshold);
|
||||
public:
|
||||
cSLIC() {}
|
||||
~cSLIC() {}
|
||||
|
||||
std::vector<int> generate_superpixels(cv::Mat image, int spixel_size_, float spatial_weight_);
|
||||
};
|
||||
|
||||
#ifdef _HFS_CUDA_ON_
|
||||
|
||||
// utils used only by GPU version of slic
|
||||
struct gSpixelInfo
|
||||
{
|
||||
Vector2f center;
|
||||
Vector4f color_info;
|
||||
int id;
|
||||
int num_pixels;
|
||||
};
|
||||
|
||||
typedef orutils::Image<gSpixelInfo> gSpixelMap;
|
||||
|
||||
namespace engines
|
||||
{
|
||||
class SegEngine
|
||||
{
|
||||
protected:
|
||||
|
||||
float max_color_dist;
|
||||
float max_xy_dist;
|
||||
|
||||
cv::Ptr<UChar4Image> source_img;
|
||||
cv::Ptr<Float4Image> cvt_img;
|
||||
cv::Ptr<IntImage> idx_img;
|
||||
|
||||
cv::Ptr<gSpixelMap> spixel_map;
|
||||
int spixel_size;
|
||||
|
||||
Vector2i img_size;
|
||||
Vector2i map_size;
|
||||
|
||||
slicSettings slic_settings;
|
||||
virtual void cvtImgSpace(cv::Ptr<UChar4Image> inimg,
|
||||
cv::Ptr<Float4Image> outimg) = 0;
|
||||
virtual void initClusterCenters() = 0;
|
||||
virtual void findCenterAssociation() = 0;
|
||||
virtual void updateClusterCenter() = 0;
|
||||
virtual void enforceConnectivity() = 0;
|
||||
|
||||
public:
|
||||
|
||||
SegEngine(const slicSettings& in_settings);
|
||||
virtual ~SegEngine();
|
||||
|
||||
const cv::Ptr<IntImage> getSegMask() const
|
||||
{
|
||||
idx_img->updateHostFromDevice();
|
||||
return idx_img;
|
||||
};
|
||||
|
||||
void setImageSize( int x, int y )
|
||||
{
|
||||
img_size.x = x;
|
||||
img_size.y = y;
|
||||
map_size.x = (int)ceil((float)x / (float)spixel_size);
|
||||
map_size.y = (int)ceil((float)y / (float)spixel_size);
|
||||
};
|
||||
|
||||
Vector2i getImageSize()
|
||||
{
|
||||
return img_size;
|
||||
};
|
||||
|
||||
void performSegmentation(cv::Ptr<UChar4Image> in_img);
|
||||
};
|
||||
|
||||
class SegEngineGPU : public SegEngine
|
||||
{
|
||||
private:
|
||||
int no_grid_per_center;
|
||||
cv::Ptr<gSpixelMap> accum_map;
|
||||
cv::Ptr<IntImage> tmp_idx_img;
|
||||
protected:
|
||||
void cvtImgSpace(cv::Ptr<UChar4Image> inimg,
|
||||
cv::Ptr<Float4Image> outimg);
|
||||
void initClusterCenters();
|
||||
void findCenterAssociation();
|
||||
void updateClusterCenter();
|
||||
void enforceConnectivity();
|
||||
public:
|
||||
SegEngineGPU(const slicSettings& in_settings);
|
||||
~SegEngineGPU();
|
||||
};
|
||||
|
||||
class CoreEngine
|
||||
{
|
||||
private:
|
||||
cv::Ptr<SegEngine> slic_seg_engine;
|
||||
|
||||
public:
|
||||
|
||||
CoreEngine(const slicSettings& in_settings);
|
||||
~CoreEngine();
|
||||
|
||||
void setImageSize(int x, int y);
|
||||
|
||||
void processFrame(cv::Ptr<UChar4Image> in_img);
|
||||
|
||||
const cv::Ptr<IntImage> getSegRes();
|
||||
};
|
||||
} // end namespace engine
|
||||
|
||||
__host__ __device__ __forceinline__ void rgb2CIELab( const Vector4u& pix_in,
|
||||
Vector4f& pix_out )
|
||||
{
|
||||
float _b = (float)pix_in.x / 255;
|
||||
float _g = (float)pix_in.y / 255;
|
||||
float _r = (float)pix_in.z / 255;
|
||||
|
||||
if (_b <= 0.04045f) _b = _b / 12.92f;
|
||||
else _b = pow( (_b + 0.055f) / 1.055f, 2.4f );
|
||||
if (_g <= 0.04045f) _g = _g / 12.92f;
|
||||
else _g = pow( (_g + 0.055f) / 1.055f, 2.4f );
|
||||
if (_r <= 0.04045f) _r = _r / 12.92f;
|
||||
else _r = pow( (_r + 0.055f) / 1.055f, 2.4f );
|
||||
|
||||
float x = _r*0.4124564f + _g*0.3575761f + _b*0.1804375f;
|
||||
float y = _r*0.2126729f + _g*0.7151522f + _b*0.0721750f;
|
||||
float z = _r*0.0193339f + _g*0.1191920f + _b*0.9503041f;
|
||||
|
||||
float epsilon = 0.008856f;
|
||||
float kappa = 903.3f;
|
||||
|
||||
float Xr = 0.950456f;
|
||||
float Yr = 1.0f;
|
||||
float Zr = 1.088754f;
|
||||
|
||||
float xr = x / Xr;
|
||||
float yr = y / Yr;
|
||||
float zr = z / Zr;
|
||||
|
||||
float fx, fy, fz;
|
||||
if ( xr > epsilon ) fx = pow( xr, 1.0f / 3.0f );
|
||||
else fx = ( kappa*xr + 16.0f ) / 116.0f;
|
||||
if ( yr > epsilon ) fy = pow( yr, 1.0f / 3.0f );
|
||||
else fy = ( kappa*yr + 16.0f ) / 116.0f;
|
||||
if ( zr > epsilon ) fz = pow( zr, 1.0f / 3.0f );
|
||||
else fz = ( kappa*zr + 16.0f ) / 116.0f;
|
||||
|
||||
pix_out.x = 116.0f*fy - 16.0f;
|
||||
pix_out.y = 500.0f*(fx - fy);
|
||||
pix_out.z = 200.0f*(fy - fz);
|
||||
}
|
||||
|
||||
__host__ __device__ __forceinline__ void initClusterCentersShared(
|
||||
const Vector4f* inimg, Vector2i map_size, Vector2i img_size,
|
||||
int spixel_size, int x, int y, cv::hfs::slic::gSpixelInfo* out_spixel)
|
||||
{
|
||||
int cluster_idx = y * map_size.x + x;
|
||||
|
||||
int img_x = x * spixel_size + spixel_size / 2;
|
||||
int img_y = y * spixel_size + spixel_size / 2;
|
||||
|
||||
img_x = img_x >= img_size.x ? (x * spixel_size + img_size.x) / 2 : img_x;
|
||||
img_y = img_y >= img_size.y ? (y * spixel_size + img_size.y) / 2 : img_y;
|
||||
|
||||
out_spixel[cluster_idx].id = cluster_idx;
|
||||
out_spixel[cluster_idx].center = Vector2f((float)img_x, (float)img_y);
|
||||
out_spixel[cluster_idx].color_info = inimg[img_y*img_size.x + img_x];
|
||||
|
||||
out_spixel[cluster_idx].num_pixels = 0;
|
||||
}
|
||||
|
||||
__host__ __device__ __forceinline__ float computeSlicDistance(
|
||||
const Vector4f& pix, int x, int y,
|
||||
const cv::hfs::slic::gSpixelInfo& center_info,
|
||||
float weight, float normalizer_xy, float normalizer_color)
|
||||
{
|
||||
float dcolor =
|
||||
(pix.x - center_info.color_info.x)*(pix.x - center_info.color_info.x)
|
||||
+ (pix.y - center_info.color_info.y)*(pix.y - center_info.color_info.y)
|
||||
+ (pix.z - center_info.color_info.z)*(pix.z - center_info.color_info.z);
|
||||
|
||||
float dxy =
|
||||
(x - center_info.center.x) * (x - center_info.center.x)
|
||||
+ (y - center_info.center.y) * (y - center_info.center.y);
|
||||
|
||||
|
||||
float retval =
|
||||
dcolor * normalizer_color + weight * dxy * normalizer_xy;
|
||||
return sqrtf(retval);
|
||||
}
|
||||
|
||||
__host__ __device__ __forceinline__ void findCenterAssociationShared(
|
||||
const Vector4f* inimg,
|
||||
const cv::hfs::slic::gSpixelInfo* in_spixel_map,
|
||||
Vector2i map_size, Vector2i img_size,
|
||||
int spixel_size, float weight, int x, int y,
|
||||
float max_xy_dist, float max_color_dist, int* out_idx_img)
|
||||
{
|
||||
int idx_img = y * img_size.x + x;
|
||||
|
||||
int ctr_x = x / spixel_size;
|
||||
int ctr_y = y / spixel_size;
|
||||
|
||||
int minidx = -1;
|
||||
float dist = 999999.9999f;
|
||||
|
||||
for ( int i = -1; i <= 1; i++ )
|
||||
for ( int j = -1; j <= 1; j++ )
|
||||
{
|
||||
int ctr_x_check = ctr_x + j;
|
||||
int ctr_y_check = ctr_y + i;
|
||||
if (ctr_x_check >= 0 && ctr_y_check >= 0 &&
|
||||
ctr_x_check < map_size.x && ctr_y_check < map_size.y)
|
||||
{
|
||||
int ctr_idx = ctr_y_check*map_size.x + ctr_x_check;
|
||||
float cdist =
|
||||
computeSlicDistance(inimg[idx_img], x, y,
|
||||
in_spixel_map[ctr_idx], weight,
|
||||
max_xy_dist, max_color_dist);
|
||||
if (cdist < dist)
|
||||
{
|
||||
dist = cdist;
|
||||
minidx = in_spixel_map[ctr_idx].id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (minidx >= 0)
|
||||
out_idx_img[idx_img] = minidx;
|
||||
}
|
||||
|
||||
__host__ __device__ __forceinline__ void finalizeReductionResultShared(
|
||||
const cv::hfs::slic::gSpixelInfo* accum_map,
|
||||
Vector2i map_size, int num_blocks_per_spixel, int x, int y,
|
||||
cv::hfs::slic::gSpixelInfo* spixel_list)
|
||||
{
|
||||
int spixel_idx = y * map_size.x + x;
|
||||
|
||||
spixel_list[spixel_idx].center = Vector2f(0, 0);
|
||||
spixel_list[spixel_idx].color_info = Vector4f(0, 0, 0, 0);
|
||||
spixel_list[spixel_idx].num_pixels = 0;
|
||||
|
||||
for (int i = 0; i < num_blocks_per_spixel; i++)
|
||||
{
|
||||
int accum_list_idx = spixel_idx * num_blocks_per_spixel + i;
|
||||
|
||||
spixel_list[spixel_idx].center +=
|
||||
accum_map[accum_list_idx].center;
|
||||
spixel_list[spixel_idx].color_info +=
|
||||
accum_map[accum_list_idx].color_info;
|
||||
spixel_list[spixel_idx].num_pixels +=
|
||||
accum_map[accum_list_idx].num_pixels;
|
||||
}
|
||||
|
||||
if (spixel_list[spixel_idx].num_pixels != 0)
|
||||
{
|
||||
spixel_list[spixel_idx].center /=
|
||||
(float)spixel_list[spixel_idx].num_pixels;
|
||||
spixel_list[spixel_idx].color_info /=
|
||||
(float)spixel_list[spixel_idx].num_pixels;
|
||||
}
|
||||
else
|
||||
{
|
||||
spixel_list[spixel_idx].center =
|
||||
Vector2f(-100, -100);
|
||||
spixel_list[spixel_idx].color_info =
|
||||
Vector4f(-100, -100, -100, -100);
|
||||
}
|
||||
}
|
||||
|
||||
__host__ __device__ __forceinline__ void supressLocalLable(
|
||||
const int* in_idx_img, Vector2i img_size,
|
||||
int x, int y, int* out_idx_img)
|
||||
{
|
||||
int clable = in_idx_img[y*img_size.x + x];
|
||||
|
||||
if (x < 2 || y < 2 || x >= img_size.x - 2 || y >= img_size.y - 2)
|
||||
{
|
||||
out_idx_img[y*img_size.x + x] = clable;
|
||||
return;
|
||||
}
|
||||
|
||||
int diff_count = 0;
|
||||
int diff_lable = -1;
|
||||
|
||||
for ( int j = -2; j <= 2; j++ )
|
||||
for ( int i = -2; i <= 2; i++ )
|
||||
{
|
||||
int nlable = in_idx_img[(y + j)*img_size.x + (x + i)];
|
||||
if (nlable != clable)
|
||||
{
|
||||
diff_lable = nlable;
|
||||
diff_count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (diff_count > 16)
|
||||
out_idx_img[y*img_size.x + x] = diff_lable;
|
||||
else
|
||||
out_idx_img[y*img_size.x + x] = clable;
|
||||
}
|
||||
|
||||
__host__ __device__ __forceinline__ void supressLocalLable2(const int* in_idx_img,
|
||||
Vector2i img_size, int x, int y, int* out_idx_img)
|
||||
{
|
||||
int pixel_idx = y*img_size.x + x;
|
||||
int clable = in_idx_img[pixel_idx];
|
||||
if (x < 1 || y < 1 || x >= img_size.x - 1 || y >= img_size.y - 1)
|
||||
{
|
||||
out_idx_img[y*img_size.x + x] = clable;
|
||||
return;
|
||||
}
|
||||
|
||||
int diff_count = 0;
|
||||
int diff_lable = -1;
|
||||
|
||||
for (int j = -1; j <= 1; j++)
|
||||
for (int i = -1; i <= 1; i++)
|
||||
{
|
||||
int nlable = in_idx_img[(y + j)*img_size.x + (x + i)];
|
||||
if (nlable != clable)
|
||||
{
|
||||
diff_lable = nlable;
|
||||
diff_count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (diff_count >= 6)
|
||||
out_idx_img[pixel_idx] = diff_lable;
|
||||
else
|
||||
out_idx_img[pixel_idx] = clable;
|
||||
}
|
||||
|
||||
__host__ __device__ __forceinline__ dim3 getGridSize( Vector2i dataSz, dim3 blockSz )
|
||||
{
|
||||
return dim3((dataSz.x + blockSz.x - 1) / blockSz.x,
|
||||
(dataSz.y + blockSz.y - 1) / blockSz.y);
|
||||
}
|
||||
|
||||
struct Float4_
|
||||
{
|
||||
__host__ __device__ Float4_() {}
|
||||
__host__ __device__ Float4_( float x_, float y_, float z_, float w_ ) {
|
||||
x = x_, y = y_, z = z_, w = w_;
|
||||
}
|
||||
volatile float x, y, z, w;
|
||||
};
|
||||
|
||||
struct Float2_
|
||||
{
|
||||
__host__ __device__ Float2_() {}
|
||||
__host__ __device__ Float2_( float x_, float y_ ) {
|
||||
x = x_, y = y_;
|
||||
}
|
||||
volatile float x, y;
|
||||
};
|
||||
|
||||
__host__ __device__ __forceinline__ Float4_ operator+= ( Float4_ &a, Float4_ b )
|
||||
{
|
||||
a.x += b.x;
|
||||
a.y += b.y;
|
||||
a.z += b.z;
|
||||
a.w += b.w;
|
||||
return a;
|
||||
}
|
||||
|
||||
__host__ __device__ __forceinline__ Float2_ operator+= ( Float2_ &a, Float2_ b )
|
||||
{
|
||||
a.x += b.x;
|
||||
a.y += b.y;
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
}}}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user