Jump Flood Algorithms for Centroidal Voronoi Tessellation
Brief
Implemented both CPU and GPU version, you could consider this as the basic playground to implement the more advanced feature such as support arbitrary shape in 2D space, or by radix-sort to restore the analytic shape of each Voronoi region etc. Another interesting application of JFA is the problem of 2D/3D level set reinitialization.
n = 16

n = 64

CPU
/**
* Copyright (c) 2014, Bo Zhou<Bo.Schwarzstein@gmail.com> and J CUBE Inc. Tokyo, Japan
* All rights reserved. * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the <organization>.
* 4. Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY COPYRIGHT HOLDER AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ #include <cmath>
#include <cstdlib>
#include <ctime> #include <ImathColor.h>
#include <ImathVec.h> #include <iostream>
#include <iterator>
#include <vector> int main( int Argc , char ** Argv )
{
-- Argc , ++ Argv ;
if ( Argc != )
{
return EXIT_FAILURE ;
} //
int NumSites = atoi( Argv[] ) ;
int Size = atoi( Argv[] ) ; // 1) Generate the 2D sites and the fill color.
//
std::vector< Imath::V2f > SiteVec ;
std::vector< int > SeedVecA( Size * Size , - ) ;
std::vector< Imath::C3c > RandomColorVec ;
if ( NumSites > )
{
srand( time(NULL) ) ; for ( int i = ; i < NumSites ; ++ i )
{
float X = static_cast< float >( rand() ) / RAND_MAX * Size ;
float Y = static_cast< float >( rand() ) / RAND_MAX * Size ; Imath::V2i Cell( static_cast< int >( floorf( X ) ) ,
static_cast< int >( floorf( Y ) ) ) ;
SiteVec.push_back( Imath::V2f( Cell.x + 0.5f , Cell.y + 0.5f ) ) ; SeedVecA[Cell.x + Cell.y * Size] = i ; Imath::C3c C( static_cast< unsigned char >( static_cast< float >( rand() ) / RAND_MAX * 255.0f ) ,
static_cast< unsigned char >( static_cast< float >( rand() ) / RAND_MAX * 255.0f ) ,
static_cast< unsigned char >( static_cast< float >( rand() ) / RAND_MAX * 255.0f ) ) ;
RandomColorVec.push_back( C ) ;
}
}
else
{
NumSites = ; SiteVec.push_back( Imath::V2f( 0.5f , 0.5f ) ) ;
SeedVecA[] = ;
RandomColorVec.push_back( Imath::C3c( , , ) ) ;
}
std::vector< int > SeedVecB( SeedVecA ) ; //
const int SizeLowTwo = static_cast< int >( ceilf( logf( static_cast< float >( Size ) ) ) ) ; //
static const Imath::V2i OffsetArray[] = { Imath::V2i( - , - ) ,
Imath::V2i( , - ) ,
Imath::V2i( , - ) ,
Imath::V2i( - , ) ,
Imath::V2i( , ) ,
Imath::V2i( - , ) ,
Imath::V2i( , ) ,
Imath::V2i( , ) } ; int * Ping = & SeedVecA[] ;
int * Pong = & SeedVecB[] ; for ( int k = Size / ; k > ; k = k >> )
{
fprintf( stdout , "k = %d\n" , k ) ; for ( int y = ; y < Size ; ++ y )
{
for ( int x = ; x < Size ; ++ x )
{
const int CellIdx = x + y * Size ;
const int Seed = Ping[CellIdx] ;
if ( Seed > - )
{
Imath::V2i Cell( x , y ) ;
for ( int i = ; i < ; ++ i )
{
const Imath::V2i & FillCell = Cell + k * OffsetArray[i] ;
if ( FillCell.x >= && FillCell.x < Size && FillCell.y >= && FillCell.y < Size )
{
const int FillCellIdx = FillCell.x + FillCell.y * Size ;
const int FillSeed = Pong[FillCellIdx] ;
if ( FillSeed < )
{
Pong[FillCellIdx] = Seed ;
}
else
{
const Imath::V2f & FillP = Imath::V2f( FillCell.x + 0.5f , FillCell.y + 0.5f ) ;
if ( ( FillP - SiteVec[Seed] ).length() < ( FillP - SiteVec[FillSeed] ).length() )
{
Pong[FillCellIdx] = Seed ;
}
}
}
}
}
}
} std::copy( Pong , Pong + SeedVecA.size() , Ping ) ;
std::swap( Ping , Pong ) ;
} //
FILE * Output = fopen( Argv[] , "wb" ) ;
fprintf( Output , "P6\n%d %d\n255\n" , Size , Size ) ; std::vector< Imath::C3c > Pixels( Size * Size , Imath::C3c( ) ) ;
for ( int y = ; y < Size ; ++ y )
{
for ( int x = ; x < Size ; ++ x )
{
const int Seed = Pong[x + y * Size] ;
if ( Seed != - )
{
Pixels[x + y * Size] = RandomColorVec[Seed] ;
}
}
} for( std::vector< Imath::V2f >::const_iterator itr = SiteVec.begin() ; itr != SiteVec.end() ; ++ itr )
{
const int x = static_cast< int >( floorf( itr->x ) ) ;
const int y = static_cast< int >( floorf( itr->y ) ) ;
Pixels[x + y * Size] = Imath::C3c( , , ) ;
} fwrite( & Pixels[].x , , Pixels.size() , Output ) ;
fclose( Output ) ; return EXIT_SUCCESS ;
}
JFA CPU
GPU
/**
* Copyright (c) 2014, Bo Zhou<Bo.Schwarzstein@gmail.com> and J CUBE Inc. Tokyo, Japan
* All rights reserved. * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the <organization>.
* 4. Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY COPYRIGHT HOLDER AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ #include <cmath>
#include <cstdio>
#include <cstdlib>
#include <ctime> #include <cuda_runtime.h>
#include <cuda_runtime_api.h> #include <iostream>
#include <iterator>
#include <vector> __global__ void Kernel( int SizeX , int SizeY , const float2 * SiteArray , const int * Ping , int * Pong , int k , int * Mutex )
{
//
const int CellX = threadIdx.x + blockIdx.x * blockDim.x ;
const int CellY = threadIdx.y + blockIdx.y * blockDim.y ; const int CellIdx = CellX + CellY * SizeX ;
const int Seed = Ping[CellIdx] ;
if ( Seed < )
{
return ;
} //
const int2 OffsetArray[] = { { - , - } ,
{ , - } ,
{ , - } ,
{ - , } ,
{ , } ,
{ - , } ,
{ , } ,
{ , } } ; for ( int i = ; i < ; ++ i )
{
const int FillCellX = CellX + k * OffsetArray[i].x ;
const int FillCellY = CellY + k * OffsetArray[i].y ;
if ( FillCellX >= && FillCellX < SizeX && FillCellY >= && FillCellY < SizeY )
{
//
const int FillCellIdx = FillCellX + FillCellY * SizeX ; // Lock
//
while ( atomicCAS( Mutex , - , FillCellIdx ) == FillCellIdx )
{
} const int FillSeed = Pong[FillCellIdx] ; if ( FillSeed < )
{
Pong[FillCellIdx] = Seed ;
}
else
{
float2 P = make_float2( FillCellX + 0.5f , FillCellY + 0.5f ) ; float2 A = SiteArray[Seed] ;
float2 PA = make_float2( A.x - P.x , A.y - P.y ) ;
float PALength = PA.x * PA.x + PA.y * PA.y ; const float2 B = SiteArray[FillSeed] ;
float2 PB = make_float2( B.x - P.x , B.y - P.y ) ;
float PBLength = PB.x * PB.x + PB.y * PB.y ; if ( PALength < PBLength )
{
Pong[FillCellIdx] = Seed ;
}
} // Release
//
atomicExch( Mutex , - ) ;
}
}
} int main( int Argc , char * Argv[] )
{
-- Argc , ++ Argv ;
if ( Argc != )
{
return EXIT_FAILURE ;
} //
int NumSites = atoi( Argv[] ) ;
int Size = atoi( Argv[] ) ; //
int NumCudaDevice = ;
cudaGetDeviceCount( & NumCudaDevice ) ;
if ( ! NumCudaDevice )
{
return EXIT_FAILURE ;
} //
//
std::vector< float2 > SiteVec ;
std::vector< int > SeedVec( Size * Size , - ) ;
std::vector< uchar3 > RandomColorVec ;
for ( int i = ; i < NumSites ; ++ i )
{
float X = static_cast< float >( rand() ) / RAND_MAX * Size ;
float Y = static_cast< float >( rand() ) / RAND_MAX * Size ;
int CellX = static_cast< int >( floorf( X ) ) ;
int CellY = static_cast< int >( floorf( Y ) ) ; SiteVec.push_back( make_float2( CellX + 0.5f , CellY + 0.5f ) ) ;
SeedVec[CellX + CellY * Size] = i ; RandomColorVec.push_back( make_uchar3( static_cast< unsigned char >( static_cast< float >( rand() ) / RAND_MAX * 255.0f ) ,
static_cast< unsigned char >( static_cast< float >( rand() ) / RAND_MAX * 255.0f ) ,
static_cast< unsigned char >( static_cast< float >( rand() ) / RAND_MAX * 255.0f ) ) ) ;
} //
size_t SiteSize = NumSites * sizeof( float2 ) ; float2 * SiteArray = NULL ;
cudaMalloc( & SiteArray , SiteSize ) ;
cudaMemcpy( SiteArray , & SiteVec[] , SiteSize , cudaMemcpyHostToDevice ) ; //
size_t BufferSize = Size * Size * sizeof( int ) ; int * Ping = NULL , * Pong = NULL ;
cudaMalloc( & Ping , BufferSize ) , cudaMemcpy( Ping , & SeedVec[] , BufferSize , cudaMemcpyHostToDevice ) ;
cudaMalloc( & Pong , BufferSize ) , cudaMemcpy( Pong , Ping , BufferSize , cudaMemcpyDeviceToDevice ) ; //
int * Mutex = NULL ;
cudaMalloc( & Mutex , sizeof( int ) ) , cudaMemset( Mutex , - , sizeof( int ) ) ; //
//
cudaDeviceProp CudaDeviceProperty ;
cudaGetDeviceProperties( & CudaDeviceProperty , ) ; dim3 BlockDim( CudaDeviceProperty.warpSize , CudaDeviceProperty.warpSize ) ;
dim3 GridDim( ( Size + BlockDim.x - ) / BlockDim.x ,
( Size + BlockDim.y - ) / BlockDim.y ) ; for ( int k = Size / ; k > ; k = k >> )
{
Kernel<<< GridDim , BlockDim >>>( Size , Size , SiteArray , Ping , Pong , k , Mutex ) ;
cudaDeviceSynchronize() ; cudaMemcpy( Ping , Pong , BufferSize , cudaMemcpyDeviceToDevice ) ;
std::swap( Ping , Pong ) ;
}
cudaMemcpy( & SeedVec[] , Pong , BufferSize , cudaMemcpyDeviceToHost ) ; //
cudaFree( SiteArray ) ;
cudaFree( Ping ) ;
cudaFree( Pong ) ;
cudaFree( Mutex ) ; //
//
FILE * Output = fopen( Argv[] , "wb" ) ;
fprintf( Output , "P6\n%d %d\n255\n" , Size , Size ) ; std::vector< uchar3 > Pixels( Size * Size ) ;
for ( int y = ; y < Size ; ++ y )
{
for ( int x = ; x < Size ; ++ x )
{
const int Seed = SeedVec[x + y * Size] ;
if ( Seed != - )
{
Pixels[x + y * Size] = RandomColorVec[Seed] ;
}
}
} for( std::vector< float2 >::const_iterator itr = SiteVec.begin() ; itr != SiteVec.end() ; ++ itr )
{
const int x = static_cast< int >( floorf( itr->x ) ) ;
const int y = static_cast< int >( floorf( itr->y ) ) ;
Pixels[x + y * Size] = make_uchar3( , , ) ;
} fwrite( & Pixels[].x , , Pixels.size() , Output ) ;
fclose( Output ) ; return EXIT_SUCCESS ;
}
JFA CUDA
Jump Flood Algorithms for Centroidal Voronoi Tessellation的更多相关文章
- Visulalization Voronoi in OpenSceneGraph
Visulalization Voronoi in OpenSceneGraph eryar@163.com Abstract. In mathematics a Voronoi diagram is ...
- Computer Graphics Research Software
Computer Graphics Research Software Helping you avoid re-inventing the wheel since 2009! Last update ...
- Delaunay Triangulation in OpenCascade
Delaunay Triangulation in OpenCascade eryar@163.com 摘要:本文简要介绍了Delaunay三角剖分的基础理论,并使用OpenCascade的三角剖分算 ...
- [转载]John Burkardt搜集的FORTRAN源代码
Over the years, I have collected, modified, adapted, adopted or created a number of software package ...
- LeetCode Questions List (LeetCode 问题列表)- Java Solutions
因为在开始写这个博客之前,已经刷了100题了,所以现在还是有很多题目没有加进来,为了方便查找哪些没加进来,先列一个表可以比较清楚的查看,也方便给大家查找.如果有哪些题目的链接有错误,请大家留言和谅解, ...
- D3、EChart、HighChart绘图demol
1.echarts: <!DOCTYPE html> <html> <head> <meta charset="utf-8" ...
- 软件项目技术点(1)——d3.interpolateZoom-在两个点之间平滑地缩放平移
AxeSlide软件项目梳理 canvas绘图系列知识点整理 软件参考d3的知识点 我们在软件中主要用到d3.js的核心函数d3.interpolateZoom - 在两个点之间平滑地缩放平移.请 ...
- 【机器学习具体解释】KNN分类的概念、误差率及其问题
转载请注明出处:http://blog.csdn.net/luoshixian099/article/details/50923056 勿在浮沙筑高台 KNN概念 KNN(K-Nearest Neig ...
- D3js-API介绍【英】
Everything in D3 is scoped under the d3 namespace. D3 uses semantic versioning. You can find the cur ...
随机推荐
- flex布局常见用法小结
1,display:flex 这个在父容器中声明: 2,flex-direction:row / column 默认为横向,也在父容器中设置,定义flex布局的主轴方向:一条轴为主轴,那么另一条轴自然 ...
- Servlet & JSP系列文章总结
前言 谢谢大家的捧场,真心感谢我的阅读者. @all 下一期,重点在 数据结构和算法 ,希望给大家带来开心.已经出了几篇,大家爱读就是我的开心. Servlet & JSP系列总结 博客, ...
- 函数式编程之-定义能够支持Partial application的函数
是时候介绍如何在F#中定义函数了,在你没有接触过函数式编程语言之前,你也许会觉得C#/Java的语法已经够丰富了,有什么任务做不了呢?当你读过函数式编程之Currying和函数式编程之Partial ...
- MySql数据库安装
MySql数据库安装 一丶数据库 什么是数据库 数据库简单连接就是存储数据的容器. 而库则是一组容器合成的东西. 也就是存储数据的.我们编程中常常会用到数据库. 什么是数据管理系统 数据库管理系统就是 ...
- 始于阿里,回归社区:阿里8个项目进入CNCF云原生全景图
破土而出的生命力,源自理想主义者心底对技术的信念. 云原生技术正席卷全球,云原生基金会在去年KubeCon +CloudNativeCon NA的现场宣布: 其正在孵化的项目已达14个,入驻的厂家或产 ...
- java ReentrantLock
介绍 ReentrantLock称为重入锁,比内部锁synchonized拥有更强大的功能,它可中断.可定时.设置公平锁 [注]使用ReentrantLock时,一定要释放锁,一般释放放到finnal ...
- [转]phpredis中文手册
本文是参考<redis中文手册>,将示例代码用php来实现,注意php-redis与redis_cli的区别(主要是返回值类型和参数用法). 目录(使用CTRL+F快速查找命令): Key ...
- SOAP系列目录
1.协议分析 2.WebService.WCF介绍 3.HttpClientHelper实现webservice调用 4.SoapCore介绍
- shiro源码篇 - 疑问解答与系列总结,你值得拥有
前言 开心一刻 小明的朋友骨折了,小明去他家里看他.他老婆很细心的为他换药,敷药,然后出去买菜.小明满脸羡慕地说:你特么真幸福啊,你老婆对你那么好!朋友哭得稀里哗啦的说:兄弟你别说了,我幸福个锤子,就 ...
- 第三方工具系列--Lombok常用注解
原创作品,可以转载,但是请标注出处地址:https://www.cnblogs.com/V1haoge/p/9329798.html Lombok注解解析: @NonNull 使用在方法的参数或者构造 ...