gaussian-filter 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/workflows/build.yml +24 -0
- data/.gitignore +9 -0
- data/.vscode/c_cpp_properties.json +19 -0
- data/.vscode/settings.json +13 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +25 -0
- data/LICENSE +21 -0
- data/NUMO.md +21 -0
- data/README.md +60 -0
- data/Rakefile +12 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/ext/Gaussian/.gitignore +3 -0
- data/ext/Gaussian/Gaussian.c +139 -0
- data/ext/Gaussian/cgaussian.c +171 -0
- data/ext/Gaussian/extconf.rb +7 -0
- data/ext/Gaussian/funcp.c +17 -0
- data/ext/Gaussian/gaussian.h +38 -0
- data/ext/Gaussian/numo-gaussian.c +148 -0
- data/ext/Gaussian/numo-gaussian.h +34 -0
- data/ext/Gaussian/rmf.sh +1 -0
- data/gaussian-filter.gemspec +22 -0
- data/install-libnarray.sh +12 -0
- data/test.rb +1 -0
- metadata +81 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 4c2cb44500e80f6377d833cc23256bedb85095047ab8fd07fc8458b45bf3fe43
|
4
|
+
data.tar.gz: bd3a28adacfd224cc7ed01a58378c78efdfafdefcf335f17cac7bdcfd206c641
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: d50458962ef63ae61fa574e8af8b0e86a747400e59927ef875d7df66030f2d916ef9a60ae1bf483b91a2cb83a920ec8e976b8d64012e93d5f0b1fe00623dcf0f
|
7
|
+
data.tar.gz: a9b6e98adcbfe4af1273a71b9229f7ac611e79ef7a446faeb2bec532dacc0817833fd6781132de68b448dbe1c85893cd07292564dff5becf8fdf267528f2a883
|
@@ -0,0 +1,24 @@
|
|
1
|
+
name: build
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
|
6
|
+
jobs:
|
7
|
+
release-versions:
|
8
|
+
name: Build ruby-filter-gaussian
|
9
|
+
runs-on: ubuntu-latest
|
10
|
+
steps:
|
11
|
+
- uses: actions/checkout@v2
|
12
|
+
- name: Set up Ruby
|
13
|
+
uses: actions/setup-ruby@v1
|
14
|
+
with:
|
15
|
+
ruby-version : 2.7
|
16
|
+
- name: Build
|
17
|
+
run: |
|
18
|
+
gem install --no-document bundler
|
19
|
+
gem build gaussian-filter.gemspec
|
20
|
+
gem install gaussian-filter-*.gem
|
21
|
+
bundle install
|
22
|
+
- name: Test
|
23
|
+
run: rake test
|
24
|
+
|
data/.gitignore
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
{
|
2
|
+
"configurations": [
|
3
|
+
{
|
4
|
+
"name": "Linux",
|
5
|
+
"includePath": [
|
6
|
+
"${workspaceFolder}/**",
|
7
|
+
"/usr/include/ruby-2.7.0",
|
8
|
+
"/usr/include/x86_64-linux-gnu/ruby-2.7.0",
|
9
|
+
"/usr/lib/x86_64-linux-gnu/ruby/vendor_ruby/2.7.0"
|
10
|
+
],
|
11
|
+
"defines": [],
|
12
|
+
"compilerPath": "/usr/bin/gcc",
|
13
|
+
"cStandard": "gnu17",
|
14
|
+
"cppStandard": "gnu++14",
|
15
|
+
"intelliSenseMode": "linux-gcc-x64"
|
16
|
+
}
|
17
|
+
],
|
18
|
+
"version": 4
|
19
|
+
}
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
gaussian-filter (0.0.1)
|
5
|
+
numo-narray
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
numo-narray (0.9.1.9)
|
11
|
+
rake (13.0.3)
|
12
|
+
rake-compiler (1.1.1)
|
13
|
+
rake
|
14
|
+
|
15
|
+
PLATFORMS
|
16
|
+
x86_64-linux
|
17
|
+
|
18
|
+
DEPENDENCIES
|
19
|
+
gaussian-filter!
|
20
|
+
numo-narray
|
21
|
+
rake (~> 13.0)
|
22
|
+
rake-compiler
|
23
|
+
|
24
|
+
BUNDLED WITH
|
25
|
+
2.2.24
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2021 MURATA Mitsuharu
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/NUMO.md
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
```sh
|
4
|
+
mkdir -p /usr/local/share
|
5
|
+
git clone --depth 1 https://github.com/ruby-numo/numo-narray.git /tmp/numo-narray
|
6
|
+
cd /tmp/numo-narray/ext/numo/narray
|
7
|
+
ruby extconf.rb
|
8
|
+
make -j
|
9
|
+
sudo mkdir -p /usr/local/include
|
10
|
+
sudo cp narray.so /usr/lib/libnarray.so
|
11
|
+
sudo cp -r numo /usr/local/include/
|
12
|
+
cd -
|
13
|
+
|
14
|
+
```
|
15
|
+
|
16
|
+
```sh
|
17
|
+
sudo rm -rf /usr/local/include/numo/
|
18
|
+
sudo rm /usr/lib/libnarray.so
|
19
|
+
rm -rf /tmp/numo-narray/
|
20
|
+
|
21
|
+
```
|
data/README.md
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
# ruby-filter-gaussian
|
2
|
+
[![build](https://github.com/Himeyama/ruby-filter-gaussian/actions/workflows/build.yml/badge.svg)](https://github.com/Himeyama/ruby-filter-gaussian/actions/workflows/build.yml)
|
3
|
+
|
4
|
+
## 概要
|
5
|
+
ガウシアンフィルターの Ruby 拡張。データが複数の場合は並列計算を行うため高速に計算されます。
|
6
|
+
|
7
|
+
基本的には、 https://docs.scipy.org/doc/scipy/reference/generated/scipy.ndimage.gaussian_filter1d.html
|
8
|
+
と同じです。
|
9
|
+
|
10
|
+
- フィルターの標準偏差に対してデータが小さい場合は計算できません。
|
11
|
+
- 実装が異なるためか Python のライブラリと比較すると丸目誤差が存在する場合があります。誤差の大きさは 10^(-15) 程度です。
|
12
|
+
|
13
|
+
## インストール
|
14
|
+
|
15
|
+
GitHub から、`ruby-filter-gaussian` をインストールするには以下のコマンドを実行します。
|
16
|
+
```sh
|
17
|
+
gem install specific_install
|
18
|
+
gem specific_install -l himeyama/ruby-filter-gaussian
|
19
|
+
```
|
20
|
+
|
21
|
+
|
22
|
+
**Gemfile** に記述する場合は以下のようにして `bundle`。
|
23
|
+
|
24
|
+
```rb
|
25
|
+
gem "gaussian-filter", github: "himeyama/ruby-filter-gaussian.git", branch: :main
|
26
|
+
```
|
27
|
+
|
28
|
+
## 使用法
|
29
|
+
<dt><code>Gaussian.filter1d(ary, sd) -> Array</code></dt>
|
30
|
+
<dd>
|
31
|
+
<p>データへガウシアンフィルター処理を行います。
|
32
|
+
`ary` の大きさが1の場合、1次元配列が返ります。
|
33
|
+
`ary` の大きさが2以上で `sd` が数値の場合は全てのデーターで `sd` が適応され、
|
34
|
+
`sd` が配列の場合は各データのインデックスに対応します。
|
35
|
+
</p>
|
36
|
+
<dl>
|
37
|
+
<dt>[PARAM] ary:</dt>
|
38
|
+
<dd>一次元のデータ</dd>
|
39
|
+
<dt>[PARAM] sd:</dt>
|
40
|
+
<dd>ガウシアンフィルターの標準偏差。</dd>
|
41
|
+
</dl>
|
42
|
+
|
43
|
+
```rb
|
44
|
+
require "Gaussian"
|
45
|
+
|
46
|
+
Gaussian.filter1d [1, 2, 3, 4, 5], 1
|
47
|
+
#=> [1.4270409503911738, 2.0678220347792573, 3.0, 3.932177965220743, 4.572959049608826]
|
48
|
+
|
49
|
+
Gaussian.filter1d [[1, 2, 3, 4, 5], [3, 2, 3, 4, 1]], 1
|
50
|
+
# =>
|
51
|
+
# [[1.4270409503911738, 2.0678220347792573, 3.0, 3.932177965220743, 4.572959049608826],
|
52
|
+
# [2.708335457918112, 2.641484411955284, 2.8831540219185285, 2.757459057400815, 2.0095670508072625]]
|
53
|
+
|
54
|
+
Gaussian.filter1d [[1, 2, 3, 4, 5], [1, 2, 3, 4, 5]], [1, 0.5]
|
55
|
+
#=>
|
56
|
+
# [[1.4270409503911738, 2.0678220347792573, 3.0, 3.932177965220743, 4.572959049608826],
|
57
|
+
# [1.1072423672218035, 2.0002638650827373, 2.9999999999999996, 3.999736134917262, 4.892757632778196]]
|
58
|
+
```
|
59
|
+
|
60
|
+
</dd>
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "bundler/setup"
|
5
|
+
require "numo/narray"
|
6
|
+
require "Gaussian"
|
7
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
8
|
+
# with your gem easier. You can also use a different console, if you like.
|
9
|
+
|
10
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
11
|
+
# require "pry"
|
12
|
+
# Pry.start
|
13
|
+
|
14
|
+
require "irb"
|
15
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
@@ -0,0 +1,139 @@
|
|
1
|
+
/*
|
2
|
+
* (c) 2021 Murata Mitsuharu
|
3
|
+
* Licensed under the MIT License.
|
4
|
+
*/
|
5
|
+
|
6
|
+
#include <stdio.h>
|
7
|
+
#include <ruby.h>
|
8
|
+
#include <ruby/intern.h>
|
9
|
+
#include <numo/narray.h>
|
10
|
+
#include <stdlib.h>
|
11
|
+
#include <pthread.h>
|
12
|
+
#include "numo-gaussian.h"
|
13
|
+
#include "gaussian.h"
|
14
|
+
|
15
|
+
extern VALUE numo_cDFloat;
|
16
|
+
VALUE cGaussian;
|
17
|
+
|
18
|
+
VALUE gaussian_filter1d_ary(VALUE self, VALUE ary, VALUE sd){
|
19
|
+
Vector filtered[16];
|
20
|
+
VALUE a;
|
21
|
+
Vector v[16];
|
22
|
+
long size[16];
|
23
|
+
pthread_t th[16];
|
24
|
+
if(TYPE(ary) != T_ARRAY) return Qfalse;
|
25
|
+
VALUE datas = rb_ary_new();
|
26
|
+
if(TYPE(rb_ary_entry(ary, 0)) != T_ARRAY)
|
27
|
+
rb_ary_store(datas, 0, ary);
|
28
|
+
else
|
29
|
+
datas = ary;
|
30
|
+
long data_size = RARRAY_LEN(datas);
|
31
|
+
if(data_size > 16) return Qfalse;
|
32
|
+
GaussianArgsRet ga[16]; ga;
|
33
|
+
a = rb_ary_new();
|
34
|
+
for(int i = 0; i < data_size; i++){
|
35
|
+
VALUE data = rb_ary_entry(datas, i);
|
36
|
+
size[i] = RARRAY_LEN(data);
|
37
|
+
v[i] = Vector_zeros(size[i]);
|
38
|
+
rb_ary_store(a, i, rb_ary_new_capa(size[i]));
|
39
|
+
for(long j = 0; j < size[i]; j++)
|
40
|
+
v[i].data[j] = NUM2DBL(rb_ary_entry(data, j));
|
41
|
+
ga[i].src_data = v[i];
|
42
|
+
ga[i].dst_data = filtered + i;
|
43
|
+
ga[i].truncate = 4.0;
|
44
|
+
if(TYPE(sd) == T_FLOAT || TYPE(sd) == T_FIXNUM){
|
45
|
+
ga[i].sd = NUM2DBL(sd);
|
46
|
+
}else if(TYPE(sd) == T_ARRAY){
|
47
|
+
if(RARRAY_LEN(sd) != data_size) return Qfalse;
|
48
|
+
ga[i].sd = NUM2DBL(rb_ary_entry(sd, i));
|
49
|
+
}else
|
50
|
+
return Qfalse;
|
51
|
+
void* (*gfunc[2])() = {gaussian, narray_gaussian};
|
52
|
+
if(pthread_create(&th[i], NULL, gfunc[0], (void*)&ga[i]))
|
53
|
+
exit(EXIT_FAILURE);
|
54
|
+
}
|
55
|
+
for(int i = 0; i < data_size; i++)
|
56
|
+
if(pthread_join(th[i], NULL))
|
57
|
+
exit(EXIT_FAILURE);
|
58
|
+
for(int i = 0; i < data_size; i++){
|
59
|
+
for(long j = 0; j < size[i]; j++){
|
60
|
+
rb_ary_store(rb_ary_entry(a, i), j, DBL2NUM(filtered[i].data[j]));
|
61
|
+
}
|
62
|
+
Vector_destroy(v[i]);
|
63
|
+
Vector_destroy(filtered[i]);
|
64
|
+
}
|
65
|
+
if(data_size == 1) return rb_ary_entry(a, 0);
|
66
|
+
return a;
|
67
|
+
}
|
68
|
+
|
69
|
+
VALUE gaussian_filter1d_dfloat(VALUE self, VALUE ary, VALUE sd){
|
70
|
+
VALUE shape = rb_funcall(ary, rb_intern("shape"), 0);
|
71
|
+
VALUE r = rb_funcall(ary, rb_intern("clone"), 0);
|
72
|
+
u64 row = 1, size;
|
73
|
+
u64 dim = NUM2INT(rb_funcall(shape, rb_intern("size"), 0));
|
74
|
+
|
75
|
+
if(dim == 1){
|
76
|
+
size = NUM2LONG(rb_ary_entry(shape, 0));
|
77
|
+
}else if(dim == 2){
|
78
|
+
row = NUM2LONG(rb_ary_entry(shape, 0));
|
79
|
+
size = NUM2LONG(rb_ary_entry(shape, 1));
|
80
|
+
}
|
81
|
+
if(TYPE(sd) == T_FLOAT || TYPE(sd) == T_FIXNUM){
|
82
|
+
VALUE tmp = rb_ary_new();
|
83
|
+
sd = rb_funcall(sd, rb_intern("to_f"), 0);
|
84
|
+
for(u64 i = 0; i < row; i++)
|
85
|
+
rb_ary_store(tmp, i, sd);
|
86
|
+
sd = tmp;
|
87
|
+
}
|
88
|
+
sd = rb_funcall(sd, rb_intern("to_a"), 0);
|
89
|
+
|
90
|
+
u64 sd_size = RARRAY_LEN(sd);
|
91
|
+
if(!(sd_size == 1 || sd_size == row)) return Qfalse;
|
92
|
+
|
93
|
+
if(dim == 1){
|
94
|
+
VALUE sp = rb_ary_new();
|
95
|
+
rb_ary_store(sp, 0, INT2NUM(1));
|
96
|
+
rb_ary_store(sp, 1, LONG2NUM(size));
|
97
|
+
VALUE a = rb_funcall(numo_cDFloat, rb_intern("zeros"), 1, sp);
|
98
|
+
rb_funcall(a, rb_intern("[]="), 2, Qtrue, ary);
|
99
|
+
return rb_funcall(gaussian_filter1d_dfloat(self, a, sd), rb_intern("[]"), 1, Qtrue);
|
100
|
+
}else if(dim == 2){
|
101
|
+
pthread_t th[row];
|
102
|
+
GaussianArgsRetRb ga[row];
|
103
|
+
for(u64 i = 0; i < row; i++){
|
104
|
+
ga[i].dst = (f64*)na_get_pointer_for_read(r);
|
105
|
+
ga[i].src = (f64*)na_get_pointer_for_read(ary);
|
106
|
+
ga[i].size = size;
|
107
|
+
ga[i].i = i;
|
108
|
+
ga[i].sd = NUM2DBL(rb_ary_entry(sd, i));
|
109
|
+
ga[i].truncate = 4.0;
|
110
|
+
if(pthread_create(th + i, NULL, (void*)_gaussian_filter1d_dfloat, (void*)(ga + i)))
|
111
|
+
exit(EXIT_FAILURE);
|
112
|
+
}
|
113
|
+
for(u64 i = 0; i < row; i++)
|
114
|
+
if(pthread_join(th[i], NULL))
|
115
|
+
exit(EXIT_FAILURE);
|
116
|
+
return r;
|
117
|
+
}
|
118
|
+
return Qfalse;
|
119
|
+
}
|
120
|
+
|
121
|
+
static VALUE gaussian_filter1d(VALUE self, VALUE ary, VALUE sd){
|
122
|
+
VALUE ary_class = rb_funcall(ary, rb_intern("class"), 0);
|
123
|
+
|
124
|
+
// rb_p(na_cast_object(ary, NA_DFLOAT));
|
125
|
+
|
126
|
+
if(rb_funcall(ary_class, rb_intern("=="), 1, numo_cDFloat) == Qtrue){
|
127
|
+
return gaussian_filter1d_dfloat(self, ary, sd);
|
128
|
+
}else if(TYPE(ary) == T_ARRAY){
|
129
|
+
return gaussian_filter1d_ary(self, ary, sd);
|
130
|
+
}
|
131
|
+
|
132
|
+
// rb_funcall(rb_stderr, rb_intern("puts"), 1, );
|
133
|
+
return Qfalse;
|
134
|
+
}
|
135
|
+
|
136
|
+
void Init_Gaussian(void){
|
137
|
+
cGaussian = rb_define_module("Gaussian");
|
138
|
+
rb_define_singleton_method(cGaussian, "filter1d", gaussian_filter1d, 2);
|
139
|
+
}
|
@@ -0,0 +1,171 @@
|
|
1
|
+
/*
|
2
|
+
* (c) 2021 Murata Mitsuharu
|
3
|
+
* Licensed under the MIT License.
|
4
|
+
* source: https://github.com/Himeyama/C-Gaussian-Filter
|
5
|
+
*/
|
6
|
+
|
7
|
+
|
8
|
+
#include <stdlib.h>
|
9
|
+
#include <stdio.h>
|
10
|
+
#include <string.h>
|
11
|
+
#include <math.h>
|
12
|
+
#include <time.h>
|
13
|
+
#include <ruby.h>
|
14
|
+
#include <numo/narray.h>
|
15
|
+
#include "gaussian.h"
|
16
|
+
|
17
|
+
|
18
|
+
void Vector_p(Vector vec){
|
19
|
+
double* data = vec.data;
|
20
|
+
char* str = (char*)malloc(100000000); // 100MB
|
21
|
+
char d[16];
|
22
|
+
for(int i = 0; i < vec.size; i++){
|
23
|
+
sprintf(d, i == vec.size - 1 ? "%f" : "%f, ", data[i]);
|
24
|
+
// \(^o^)/
|
25
|
+
strcat(str, d);
|
26
|
+
}
|
27
|
+
printf("[%s]\n", str);
|
28
|
+
}
|
29
|
+
|
30
|
+
void Vector_txt(Vector vec){
|
31
|
+
double* data = vec.data;
|
32
|
+
char* str = (char*)malloc(100000000); // 100MB
|
33
|
+
char d[16];
|
34
|
+
for(int i = 0; i < vec.size; i++){
|
35
|
+
sprintf(d, "%f\n", data[i]);
|
36
|
+
// \(^o^)/
|
37
|
+
strcat(str, d);
|
38
|
+
}
|
39
|
+
printf("%s", str);
|
40
|
+
}
|
41
|
+
|
42
|
+
void Vector_destroy(Vector vec){
|
43
|
+
free(vec.data);
|
44
|
+
}
|
45
|
+
|
46
|
+
Vector Vector_initialize(long size){
|
47
|
+
Vector vec;
|
48
|
+
vec.size = size;
|
49
|
+
vec.data = (double*)malloc(sizeof(double) * size);
|
50
|
+
return vec;
|
51
|
+
}
|
52
|
+
|
53
|
+
Vector Vector_initializeP(long size, Vector* vec){
|
54
|
+
vec->size = size;
|
55
|
+
vec->data = (double*)malloc(sizeof(double) * size);
|
56
|
+
return *vec;
|
57
|
+
}
|
58
|
+
|
59
|
+
Vector Vector_zeros(long size){
|
60
|
+
Vector vec = Vector_initialize(size);
|
61
|
+
for(int i = 0; i < size; i++)
|
62
|
+
vec.data[i] = 0;
|
63
|
+
return vec;
|
64
|
+
}
|
65
|
+
|
66
|
+
double Vector_dot(Vector vec1, Vector vec2){
|
67
|
+
if(vec1.size != vec2.size){
|
68
|
+
fprintf(stderr, "ベクトルのサイズが異なります\n");
|
69
|
+
exit(EXIT_FAILURE);
|
70
|
+
}
|
71
|
+
double dot = 0;
|
72
|
+
for(int i = 0; i < vec1.size; i++){
|
73
|
+
dot += vec1.data[i] * vec2.data[i];
|
74
|
+
}
|
75
|
+
return dot;
|
76
|
+
}
|
77
|
+
|
78
|
+
Vector Vector_arange(int start, int stop){
|
79
|
+
int size = stop - start;
|
80
|
+
Vector vec = Vector_initialize(size);
|
81
|
+
for(int i = 0; i < size; i++){
|
82
|
+
vec.data[i] = start + i;
|
83
|
+
}
|
84
|
+
return vec;
|
85
|
+
}
|
86
|
+
|
87
|
+
double Vector_sum(Vector vec){
|
88
|
+
double sum = 0;
|
89
|
+
for(int i = 0; i < vec.size; i++)
|
90
|
+
sum += vec.data[i];
|
91
|
+
return sum;
|
92
|
+
}
|
93
|
+
|
94
|
+
// 破壊的関数
|
95
|
+
void Vector_div(Vector vec, double n){
|
96
|
+
for(int i = 0; i < vec.size; i++){
|
97
|
+
vec.data[i] /= n;
|
98
|
+
}
|
99
|
+
}
|
100
|
+
|
101
|
+
// 正規分布 (0, 1) に従う乱数
|
102
|
+
Vector Vector_normal(long size){
|
103
|
+
Vector vec = Vector_initialize(size);
|
104
|
+
for(int i = 0; i < size; i++){
|
105
|
+
double u1 = drand48();
|
106
|
+
double u2 = drand48();
|
107
|
+
vec.data[i] = sqrt(-2 * log(u1)) * sin(2 * M_PI * u2);
|
108
|
+
}
|
109
|
+
return vec;
|
110
|
+
}
|
111
|
+
|
112
|
+
Vector Vector_clone(Vector vec){
|
113
|
+
Vector c = Vector_initialize(vec.size);
|
114
|
+
for(int i = 0; i < vec.size; i++)
|
115
|
+
c.data[i] = vec.data[i];
|
116
|
+
return c;
|
117
|
+
}
|
118
|
+
|
119
|
+
void* gaussian(GaussianArgsRet* ga){
|
120
|
+
Vector src_data = ga->src_data;
|
121
|
+
double sd = ga->sd;
|
122
|
+
double truncate = ga->truncate;
|
123
|
+
|
124
|
+
// printf("sd: %lf\n", sd);
|
125
|
+
// printf("truncate: %lf\n", truncate);
|
126
|
+
// Vector_p(src_data);
|
127
|
+
|
128
|
+
int r = (int)(truncate * sd + 0.5);
|
129
|
+
|
130
|
+
if(r > src_data.size){
|
131
|
+
fprintf(stderr, "データが小さすぎます\n");
|
132
|
+
exit(EXIT_FAILURE);
|
133
|
+
}
|
134
|
+
|
135
|
+
Vector data = Vector_initialize(src_data.size + 2 * r);
|
136
|
+
for(int i = 0; i < r; i++)
|
137
|
+
data.data[i] = src_data.data[r-i-1];
|
138
|
+
for(int i = r; i < src_data.size + r; i++)
|
139
|
+
data.data[i] = src_data.data[i-r];
|
140
|
+
for(int i = 0; i < r; i++)
|
141
|
+
data.data[i+r+src_data.size] = src_data.data[src_data.size-i-1];
|
142
|
+
|
143
|
+
Vector f = Vector_initialize(data.size);
|
144
|
+
|
145
|
+
Vector x = Vector_arange(-r, r+1);
|
146
|
+
Vector gauss = Vector_zeros(2*r+1);
|
147
|
+
for(int i = 0; i < x.size; i++){
|
148
|
+
gauss.data[i] = exp(-0.5 * x.data[i] * x.data[i] / (sd * sd));
|
149
|
+
}
|
150
|
+
Vector_div(gauss, Vector_sum(gauss));
|
151
|
+
|
152
|
+
for(int i = r; i < data.size - r; i++){
|
153
|
+
Vector d;
|
154
|
+
d.size = 2 * r + 1;
|
155
|
+
d.data = data.data + i - r;
|
156
|
+
f.data[i] = Vector_dot(gauss, d);
|
157
|
+
}
|
158
|
+
|
159
|
+
Vector *filtered = ga->dst_data;
|
160
|
+
Vector_initializeP(src_data.size, filtered);
|
161
|
+
for(int i = 0; i < filtered->size; i++){
|
162
|
+
filtered->data[i] = f.data[i + r];
|
163
|
+
}
|
164
|
+
|
165
|
+
Vector_destroy(data);
|
166
|
+
Vector_destroy(f);
|
167
|
+
Vector_destroy(x);
|
168
|
+
Vector_destroy(gauss);
|
169
|
+
|
170
|
+
return NULL;
|
171
|
+
}
|
@@ -0,0 +1,38 @@
|
|
1
|
+
/*
|
2
|
+
* (c) 2021 Murata Mitsuharu
|
3
|
+
* Licensed under the MIT License.
|
4
|
+
* source: https://github.com/Himeyama/C-Gaussian-Filter
|
5
|
+
*/
|
6
|
+
|
7
|
+
|
8
|
+
#ifndef GAUSSIAN_H
|
9
|
+
#define GAUSSIAN_H
|
10
|
+
|
11
|
+
struct vector{
|
12
|
+
long size;
|
13
|
+
double* data;
|
14
|
+
};
|
15
|
+
|
16
|
+
typedef struct vector Vector;
|
17
|
+
|
18
|
+
typedef struct{
|
19
|
+
Vector src_data;
|
20
|
+
Vector* dst_data;
|
21
|
+
double sd;
|
22
|
+
double truncate;
|
23
|
+
} GaussianArgsRet;
|
24
|
+
|
25
|
+
void Vector_p(Vector vec);
|
26
|
+
void Vector_txt(Vector vec);
|
27
|
+
void Vector_destroy(Vector vec);
|
28
|
+
Vector Vector_initialize(long size);
|
29
|
+
Vector Vector_zeros(long size);
|
30
|
+
double Vector_dot(Vector vec1, Vector vec2);
|
31
|
+
Vector Vector_arange(int start, int stop);
|
32
|
+
double Vector_sum(Vector vec);
|
33
|
+
void Vector_div(Vector vec, double n);
|
34
|
+
Vector Vector_normal(long size);
|
35
|
+
Vector Vector_clone(Vector vec);
|
36
|
+
void* gaussian(GaussianArgsRet* ga);
|
37
|
+
|
38
|
+
#endif
|
@@ -0,0 +1,148 @@
|
|
1
|
+
/*
|
2
|
+
* (c) 2021 Murata Mitsuharu
|
3
|
+
* Licensed under the MIT License.
|
4
|
+
*/
|
5
|
+
|
6
|
+
#include <ruby/ruby.h>
|
7
|
+
#include <numo/narray.h>
|
8
|
+
#include "numo-gaussian.h"
|
9
|
+
|
10
|
+
f64 getData(f64* data, u64 idx){
|
11
|
+
return 0;
|
12
|
+
}
|
13
|
+
|
14
|
+
f64 conv1(f64* data, f64 idx, u32 r){
|
15
|
+
for(i64 i = idx - r; i <= idx + r; i++){
|
16
|
+
printf("%ld\n", i);
|
17
|
+
}
|
18
|
+
return 0;
|
19
|
+
}
|
20
|
+
|
21
|
+
// index 取得
|
22
|
+
i64 get_at(i64 i, i64 n){
|
23
|
+
i64 idx;
|
24
|
+
if(i >= -n && i < 2 * n){
|
25
|
+
idx = i < 0 ? - i - 1 : (n <= i ? 2 * n - i - 1 : i);
|
26
|
+
// printf("INDEX: %ld\n",idx);
|
27
|
+
return idx;
|
28
|
+
}
|
29
|
+
return -1;
|
30
|
+
}
|
31
|
+
|
32
|
+
// 数値のポインタを返す
|
33
|
+
f64* get_mat_at(f64* x, i64 n, i64 i){
|
34
|
+
i64 idx = get_at(i, n);
|
35
|
+
if(idx == -1) return NULL;
|
36
|
+
return x + idx;
|
37
|
+
}
|
38
|
+
|
39
|
+
f64 n_dot(i64 n, i64 r, i64 size, f64 *x, i64 i, f64 *gk){
|
40
|
+
f64 sum = 0;
|
41
|
+
f64* tmp;
|
42
|
+
for(i64 j = 0; j < n; j++){
|
43
|
+
tmp = get_mat_at(x, size, j+i-r);
|
44
|
+
// printf("%f * %f\n", gk[j], *tmp);
|
45
|
+
if(tmp == NULL) return NAN;
|
46
|
+
sum += gk[j] * *tmp;
|
47
|
+
}
|
48
|
+
// puts("OK");
|
49
|
+
return sum;
|
50
|
+
}
|
51
|
+
|
52
|
+
// ガウシアンフィルターの重み配列生成
|
53
|
+
// sd: 標準偏差
|
54
|
+
// n: カーネルの大きさ (n * 2 + 1)
|
55
|
+
f64* gaussian_kernel(f64 sd, i64 n){
|
56
|
+
f64* w = (f64*)malloc(sizeof(f64) * (2 * n + 1));
|
57
|
+
f64 sum = 0;
|
58
|
+
for(i64 i = -n; i <= n; i++)
|
59
|
+
sum += (w[i+n] = exp(-0.5 * i * i / (sd * sd)));
|
60
|
+
for(i64 i = -n; i <= n; i++)
|
61
|
+
w[i+n] /= sum;
|
62
|
+
return w;
|
63
|
+
}
|
64
|
+
|
65
|
+
|
66
|
+
f64* n_gauss_func(i64 r, f64 sd){
|
67
|
+
f64* g = (f64*)malloc(sizeof(f64)*(2*r+1));
|
68
|
+
f64 sum = 0;
|
69
|
+
for(i64 i = -r; i <= r; i++){
|
70
|
+
g[i+r] = exp(-0.5 * i * i / (sd * sd));
|
71
|
+
sum += g[i+r];
|
72
|
+
}
|
73
|
+
for(i64 i = -r; i <= r; i++)
|
74
|
+
g[i+r] /= sum;
|
75
|
+
return g;
|
76
|
+
}
|
77
|
+
|
78
|
+
|
79
|
+
// データの両端部分を補完
|
80
|
+
// v: 配列
|
81
|
+
// n: 配列の大きさ
|
82
|
+
// len: 片端補完サイズ
|
83
|
+
f64* dreflect(f64 *v, i64 n, i64 len){
|
84
|
+
if(n < len){
|
85
|
+
fprintf(stderr, "エラー: 両端の大きさが元の配列より大きいため、補完できません。\n");
|
86
|
+
return NULL;
|
87
|
+
};
|
88
|
+
i64 r_size = n + 2 * len;
|
89
|
+
f64* r = (f64*)malloc(sizeof(f64) * r_size);
|
90
|
+
for(i64 i = 0; i < n; i++){
|
91
|
+
r[len + i] = v[i];
|
92
|
+
}
|
93
|
+
for(i64 i = 0; i < len; i++){
|
94
|
+
r[len - i - 1] = v[i];
|
95
|
+
r[len + n + i] = v[n - i - 1];
|
96
|
+
}
|
97
|
+
return r;
|
98
|
+
}
|
99
|
+
|
100
|
+
f64* correlate1d(f64* input, i64 input_size, f64* weights, i64 weights_size, f64* dst){
|
101
|
+
i64 n = input_size - weights_size;
|
102
|
+
f64* r = dst;
|
103
|
+
for(i64 i = 0; i <= n; i++){
|
104
|
+
f64 sum = 0;
|
105
|
+
for(i64 j = 0; j < weights_size; j++)
|
106
|
+
sum += weights[weights_size - j - 1] * input[i + j];
|
107
|
+
r[i] = sum;
|
108
|
+
}
|
109
|
+
return r;
|
110
|
+
}
|
111
|
+
|
112
|
+
|
113
|
+
// 反転したベクトルを返します
|
114
|
+
// v: 配列
|
115
|
+
// size: 配列の大きさ
|
116
|
+
f64* dreverse(f64 v[], i64 size){
|
117
|
+
f64* r = malloc(sizeof(f64) * size);
|
118
|
+
for(i64 i = 0; i < size; i++)
|
119
|
+
r[i] = v[size-i-1];
|
120
|
+
return r;
|
121
|
+
}
|
122
|
+
|
123
|
+
|
124
|
+
void* _gaussian_filter1d_dfloat(GaussianArgsRetRb* ga){
|
125
|
+
f64* dst = ga->dst;
|
126
|
+
f64* src = ga->src;
|
127
|
+
i64 size = ga->size;
|
128
|
+
dst += size * ga->i;
|
129
|
+
src += size * ga->i;
|
130
|
+
f64 sd = ga->sd;
|
131
|
+
f64 truncate = ga->truncate;
|
132
|
+
i64 t = (i64)(truncate * sd + 0.5);
|
133
|
+
if(t > size){
|
134
|
+
fprintf(stderr, "データが小さすぎます\n");
|
135
|
+
exit(EXIT_FAILURE);
|
136
|
+
}
|
137
|
+
// i64 gs = 2 * t + 1;
|
138
|
+
f64* tmp = gaussian_kernel(sd, t);
|
139
|
+
f64* weights = dreverse(tmp, 2 * t + 1);
|
140
|
+
f64* s = dreflect(src, size, t);
|
141
|
+
correlate1d(s, 2 * t + size, weights, 2 * t + 1, dst);
|
142
|
+
|
143
|
+
free(tmp);
|
144
|
+
free(weights);
|
145
|
+
free(s);
|
146
|
+
|
147
|
+
return NULL;
|
148
|
+
}
|
@@ -0,0 +1,34 @@
|
|
1
|
+
#ifndef NUMO_GAUSSIAN_H
|
2
|
+
#define NUMO_GAUSSIAN_H
|
3
|
+
|
4
|
+
// typedef narray_t* NArray;
|
5
|
+
typedef size_t SIZE;
|
6
|
+
typedef unsigned char u8;
|
7
|
+
typedef __int64_t i64;
|
8
|
+
typedef __uint32_t u32;
|
9
|
+
typedef __uint64_t u64;
|
10
|
+
typedef double f64;
|
11
|
+
typedef u64 VALUE;
|
12
|
+
|
13
|
+
typedef struct{
|
14
|
+
VALUE src_data;
|
15
|
+
VALUE dst_data;
|
16
|
+
f64 sd;
|
17
|
+
f64 truncate;
|
18
|
+
} GaussianNArrayArgsRet;
|
19
|
+
|
20
|
+
typedef struct{
|
21
|
+
f64* src;
|
22
|
+
f64* dst;
|
23
|
+
VALUE size;
|
24
|
+
f64 sd;
|
25
|
+
f64 truncate;
|
26
|
+
u64 i;
|
27
|
+
} GaussianArgsRetRb;
|
28
|
+
|
29
|
+
f64 getData(f64* data, u64 idx);
|
30
|
+
f64 conv1(f64* data, f64 idx, u32 r);
|
31
|
+
void* narray_gaussian(GaussianNArrayArgsRet* ga);
|
32
|
+
void* _gaussian_filter1d_dfloat(GaussianArgsRetRb* ga);
|
33
|
+
|
34
|
+
#endif
|
data/ext/Gaussian/rmf.sh
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rm *.o *.so Makefile
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# require_relative "lib/gaussian/filter/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "gaussian-filter"
|
7
|
+
spec.version = "0.0.3"
|
8
|
+
spec.authors = ["Murata Mitsuharu"]
|
9
|
+
spec.email = ["hikari.photon+dev@gmail.com"]
|
10
|
+
spec.summary = "Gaussian Filter"
|
11
|
+
spec.homepage = "https://himeyama.github.io"
|
12
|
+
spec.required_ruby_version = ">= 2.4.0"
|
13
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
14
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
|
15
|
+
end
|
16
|
+
spec.bindir = "exe"
|
17
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
18
|
+
spec.require_paths = ["ext"]
|
19
|
+
spec.extensions = %w[ext/Gaussian/extconf.rb]
|
20
|
+
|
21
|
+
spec.add_dependency "numo-narray"
|
22
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
mkdir -p /usr/local/share
|
4
|
+
git clone --depth 1 https://github.com/ruby-numo/numo-narray.git /tmp/numo-narray
|
5
|
+
cd /tmp/numo-narray/ext/numo/narray
|
6
|
+
ruby extconf.rb
|
7
|
+
make -j
|
8
|
+
sudo mkdir -p /usr/local/include
|
9
|
+
sudo cp narray.so /usr/lib/libnarray.so
|
10
|
+
sudo cp -r numo /usr/local/include/
|
11
|
+
rm -rf /tmp/numo-narray/
|
12
|
+
cd -
|
data/test.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "gem"
|
metadata
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: gaussian-filter
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.3
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Murata Mitsuharu
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-09-09 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: numo-narray
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
description:
|
28
|
+
email:
|
29
|
+
- hikari.photon+dev@gmail.com
|
30
|
+
executables: []
|
31
|
+
extensions:
|
32
|
+
- ext/Gaussian/extconf.rb
|
33
|
+
extra_rdoc_files: []
|
34
|
+
files:
|
35
|
+
- ".github/workflows/build.yml"
|
36
|
+
- ".gitignore"
|
37
|
+
- ".vscode/c_cpp_properties.json"
|
38
|
+
- ".vscode/settings.json"
|
39
|
+
- Gemfile
|
40
|
+
- Gemfile.lock
|
41
|
+
- LICENSE
|
42
|
+
- NUMO.md
|
43
|
+
- README.md
|
44
|
+
- Rakefile
|
45
|
+
- bin/console
|
46
|
+
- bin/setup
|
47
|
+
- ext/Gaussian/.gitignore
|
48
|
+
- ext/Gaussian/Gaussian.c
|
49
|
+
- ext/Gaussian/cgaussian.c
|
50
|
+
- ext/Gaussian/extconf.rb
|
51
|
+
- ext/Gaussian/funcp.c
|
52
|
+
- ext/Gaussian/gaussian.h
|
53
|
+
- ext/Gaussian/numo-gaussian.c
|
54
|
+
- ext/Gaussian/numo-gaussian.h
|
55
|
+
- ext/Gaussian/rmf.sh
|
56
|
+
- gaussian-filter.gemspec
|
57
|
+
- install-libnarray.sh
|
58
|
+
- test.rb
|
59
|
+
homepage: https://himeyama.github.io
|
60
|
+
licenses: []
|
61
|
+
metadata: {}
|
62
|
+
post_install_message:
|
63
|
+
rdoc_options: []
|
64
|
+
require_paths:
|
65
|
+
- ext
|
66
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: 2.4.0
|
71
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
requirements: []
|
77
|
+
rubygems_version: 3.2.1
|
78
|
+
signing_key:
|
79
|
+
specification_version: 4
|
80
|
+
summary: Gaussian Filter
|
81
|
+
test_files: []
|