gaussian-filter 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
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,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ *.so
@@ -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
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "files.associations": {
3
+ "numo-gaussian.h": "c",
4
+ "narray.h": "c",
5
+ "template.h": "c",
6
+ "stdio.h": "c",
7
+ "ruby.h": "c",
8
+ "intern.h": "c",
9
+ "types.h": "c",
10
+ "narray_config.h": "c",
11
+ "stdlib.h": "c"
12
+ }
13
+ }
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ # Specify your gem's dependencies in gaussian-filter.gemspec
6
+ gemspec
7
+
8
+ gem "rake", "~> 13.0"
9
+ gem "numo-narray"
10
+ gem "rake-compiler"
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
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ task default: %i[]
5
+
6
+ require "rake/extensiontask"
7
+
8
+ Rake::ExtensionTask.new "Gaussian" do |ext|
9
+ ext.lib_dir = "ext"
10
+ end
11
+
12
+ task :default => :compile
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,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,3 @@
1
+ Makefile
2
+ *.o
3
+ *.out
@@ -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,7 @@
1
+ require 'mkmf'
2
+
3
+ narray_dir = Gem.find_files("numo").map{|e| e.include?("narray") ? e : false}.select{|e| e}.to_a[0]
4
+ $INCFLAGS += " -I#{narray_dir}"
5
+ $libs += " #{narray_dir}/narray.so"
6
+
7
+ create_makefile "Gaussian"
@@ -0,0 +1,17 @@
1
+ #include <stdio.h>
2
+
3
+ void* func1(void){
4
+ puts("Hello, world!");
5
+ return NULL;
6
+ }
7
+
8
+ void* func2(void){
9
+ puts("こんにちは世界");
10
+ return NULL;
11
+ }
12
+
13
+ int main(void){
14
+ void* (*a[2])() = {func1, func2};
15
+ a[1]();
16
+ return 0;
17
+ }
@@ -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
@@ -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: []