gaussian-filter 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
[](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: []
|