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 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: []