compix 0.1.1 → 0.2.1
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 +4 -4
- data/ext/compix/compix.c +26 -42
- data/ext/compix/compix.h +2 -15
- data/ext/compix/compix_helpers.c +51 -0
- data/ext/compix/compix_helpers.h +32 -0
- data/lib/compix.rb +20 -0
- data/lib/compix/match.rb +24 -2
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 573a0eea05badf4bd1964736361513caeed36ecb
|
4
|
+
data.tar.gz: 952fc5643ce5a5fd16b9f45d540f7bb101c14ca0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a0fd67bdf4fbfb99f753aed312fea832dffe4fcb3713565b54cc2337ef115440226a8c5cba4e39e1138b39de9e277f3b04c56446198af423076a06910355d700
|
7
|
+
data.tar.gz: 98ec2b5321a0e51d7476db720fab5965afe10ffe691325f937abab55454b8f7dafeb5aed224594f671f7fc71f336ff2e778c47d41744c8d84228903132f033e7
|
data/ext/compix/compix.c
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
|
6
6
|
void Init_compix(){
|
7
7
|
VALUE CompixModule = rb_define_module("Compix");
|
8
|
-
rb_define_singleton_method(CompixModule, "find_subimage", find_subimage,
|
8
|
+
rb_define_singleton_method(CompixModule, "find_subimage", find_subimage, -1);
|
9
9
|
}
|
10
10
|
|
11
11
|
bool compare_pixels(PIXEL pone, PIXEL ptwo, int threshold){
|
@@ -23,7 +23,7 @@ bool compare_pixels(PIXEL pone, PIXEL ptwo, int threshold){
|
|
23
23
|
return true;
|
24
24
|
}
|
25
25
|
|
26
|
-
int compare_at(PIXEL *pixelsSmall, PIXEL *pixelsBig, int
|
26
|
+
int compare_at(PIXEL *pixelsSmall, PIXEL *pixelsBig, int color_threshold, int bigXoffset, int bigYoffset,
|
27
27
|
int siwidth, int siheight, int sswidth, int ssheight){
|
28
28
|
PIXEL firstPixel;
|
29
29
|
PIXEL secPixel;
|
@@ -41,7 +41,7 @@ int compare_at(PIXEL *pixelsSmall, PIXEL *pixelsBig, int thres, int bigXoffset,
|
|
41
41
|
break;
|
42
42
|
}
|
43
43
|
secPixel = pixelsBig[bigCoord];
|
44
|
-
if(compare_pixels(firstPixel, secPixel,
|
44
|
+
if(compare_pixels(firstPixel, secPixel, color_threshold)){
|
45
45
|
match++;
|
46
46
|
}
|
47
47
|
else {
|
@@ -55,57 +55,49 @@ int compare_at(PIXEL *pixelsSmall, PIXEL *pixelsBig, int thres, int bigXoffset,
|
|
55
55
|
return match;
|
56
56
|
}
|
57
57
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
int
|
58
|
+
// (VALUE self, VALUE subimage, VALUE bigimage, VALUE options)
|
59
|
+
VALUE find_subimage(int argc, VALUE* argv, VALUE self){
|
60
|
+
VALUE subimage = argv[0];
|
61
|
+
VALUE image = argv[1];
|
62
|
+
VALUE options_hash;
|
63
|
+
int color_threshold = 0;
|
64
|
+
double pixels_threshold = 0;
|
65
|
+
int xstart = 0;
|
66
|
+
int ystart = 0 ;
|
64
67
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
68
|
+
if(argc == 3){
|
69
|
+
options_hash = argv[2];
|
70
|
+
color_threshold = integer_from_hash(options_hash, "threshold", 0, 0, 255);
|
71
|
+
xstart = integer_from_hash(options_hash, "start_coordinate_x", 0, 0, INT_MAX);
|
72
|
+
ystart = integer_from_hash(options_hash, "start_coordinate_y", 0, 0, INT_MAX);
|
73
|
+
pixels_threshold = float_from_hash(options_hash, "pixels_threshold", 0.85, 0.0, 1.0);
|
69
74
|
}
|
70
|
-
return bytearray_ptr;
|
71
|
-
}
|
72
75
|
|
73
|
-
VALUE find_subimage(VALUE self, VALUE subimage, VALUE bigimage, VALUE threshold){
|
74
76
|
VALUE subimage_match_obj;
|
75
77
|
|
76
78
|
int siwidth = NUM2INT(rb_funcall(subimage, rb_intern("width"), 0));
|
77
79
|
int siheight = NUM2INT(rb_funcall(subimage, rb_intern("height"), 0));
|
78
|
-
int sswidth = NUM2INT(rb_funcall(
|
79
|
-
int ssheight = NUM2INT(rb_funcall(
|
80
|
+
int sswidth = NUM2INT(rb_funcall(image, rb_intern("width"), 0));
|
81
|
+
int ssheight = NUM2INT(rb_funcall(image, rb_intern("height"), 0));
|
80
82
|
|
81
83
|
PIXEL *bytearray_subimg = malloc(siwidth * siheight * sizeof(PIXEL));
|
82
84
|
PIXEL *bytearray_big_image = malloc(sswidth * ssheight * sizeof(PIXEL));
|
83
|
-
|
84
|
-
int thres = NUM2UINT(threshold);
|
85
|
+
|
85
86
|
int match = 0;
|
86
87
|
int maxmatch = 0;
|
87
88
|
int maxX = -1;
|
88
89
|
int maxY = -1;
|
89
|
-
|
90
|
-
//int yTopLimit = NUM2INT(rb_ary_entry(minCoord, 1));
|
91
|
-
//int xRightLimit = NUM2INT(rb_ary_entry(maxCoord, 0));
|
92
|
-
//int yBottomLimit = NUM2INT(rb_ary_entry(maxCoord, 1));
|
93
|
-
// I didn't want to break backwards compatibility, so while this is less legible
|
94
|
-
// and slower if old version of compix is used, it will still work.
|
95
|
-
// The third and fourth entry in the array specifies from where to start checking the big image.
|
96
|
-
// Used for e.g. findAllSubImages in rubypng
|
97
|
-
int xstart = 0; //NUM2INT(rb_ary_entry(minCoord, 2));
|
98
|
-
int ystart = 0 ; //NUM2INT(rb_ary_entry(minCoord, 3));
|
90
|
+
|
99
91
|
int x, y;
|
100
92
|
int compPix = siwidth * siheight;
|
101
93
|
|
102
94
|
// Create bytearrays for pixels
|
103
95
|
bytearray_subimg = image_to_bytearray(bytearray_subimg, subimage);
|
104
|
-
bytearray_big_image = image_to_bytearray(bytearray_big_image,
|
96
|
+
bytearray_big_image = image_to_bytearray(bytearray_big_image, image);
|
105
97
|
|
106
98
|
for(y = ystart ; y <= ssheight - siheight; y++){
|
107
99
|
for(x = xstart ; x <= sswidth - siwidth; x++){
|
108
|
-
match = compare_at(bytearray_subimg, bytearray_big_image,
|
100
|
+
match = compare_at(bytearray_subimg, bytearray_big_image, color_threshold, x, y,
|
109
101
|
siwidth, siheight, sswidth, ssheight);
|
110
102
|
if(match > maxmatch){
|
111
103
|
maxmatch = match;
|
@@ -113,20 +105,12 @@ VALUE find_subimage(VALUE self, VALUE subimage, VALUE bigimage, VALUE threshold)
|
|
113
105
|
maxY = y;
|
114
106
|
}
|
115
107
|
}
|
108
|
+
xstart = 0;
|
116
109
|
}
|
117
110
|
|
118
111
|
free(bytearray_subimg);
|
119
112
|
free(bytearray_big_image);
|
120
113
|
|
121
|
-
subimage_match_obj = initialize_subimage_match_obj(maxX, maxY, compPix, maxmatch);
|
114
|
+
subimage_match_obj = initialize_subimage_match_obj(maxX, maxY, compPix, maxmatch, siwidth, siheight, pixels_threshold);
|
122
115
|
return subimage_match_obj;
|
123
116
|
}
|
124
|
-
|
125
|
-
VALUE initialize_subimage_match_obj(int coord_x, int coord_y, int pixels_compared, int pixels_matched){
|
126
|
-
VALUE mCompixModule = rb_const_get(rb_cObject, rb_intern("Compix"));
|
127
|
-
VALUE cSubimageMatch = rb_const_get(mCompixModule, rb_intern("SubimageMatch"));
|
128
|
-
|
129
|
-
VALUE match_obj = rb_funcall(cSubimageMatch, rb_intern("new"), 4, INT2NUM(coord_x), INT2NUM(coord_y),
|
130
|
-
INT2NUM(pixels_compared), INT2NUM(pixels_matched));
|
131
|
-
return match_obj;
|
132
|
-
}
|
data/ext/compix/compix.h
CHANGED
@@ -3,29 +3,16 @@
|
|
3
3
|
|
4
4
|
#include <ruby.h>
|
5
5
|
#include <stdbool.h>
|
6
|
+
#include "compix_helpers.h"
|
6
7
|
|
7
8
|
|
8
|
-
|
9
|
-
// Types and macros from OilyPNG for compatibility
|
10
|
-
typedef uint32_t PIXEL; // Pixels use 32 bits unsigned integers
|
11
|
-
typedef unsigned char BYTE; // Bytes use 8 bits unsigned integers
|
12
|
-
#define R_BYTE(pixel) ((BYTE) (((pixel) & (PIXEL) 0xff000000) >> 24))
|
13
|
-
#define G_BYTE(pixel) ((BYTE) (((pixel) & (PIXEL) 0x00ff0000) >> 16))
|
14
|
-
#define B_BYTE(pixel) ((BYTE) (((pixel) & (PIXEL) 0x0000ff00) >> 8))
|
15
|
-
#define A_BYTE(pixel) ((BYTE) (((pixel) & (PIXEL) 0x000000ff)))
|
16
|
-
|
17
9
|
void Init_compix();
|
18
10
|
|
19
|
-
VALUE find_subimage(
|
20
|
-
|
21
|
-
VALUE initialize_subimage_match_obj(int coord_x, int coord_y, int pixels_compared, int pixels_matched);
|
11
|
+
VALUE find_subimage(int argc, VALUE* argv, VALUE self);
|
22
12
|
|
23
13
|
int compare_at(PIXEL *pixelsSmall, PIXEL *pixelsBig, int thres, int bigXoffset, int bigYoffset,
|
24
14
|
int siwidth, int siheight, int sswidth, int ssheight);
|
25
15
|
|
26
16
|
bool compare_pixels(PIXEL pone, PIXEL ptwo, int threshold);
|
27
17
|
|
28
|
-
// The bytearray_ptr should be allocated for the correct size.
|
29
|
-
PIXEL* image_to_bytearray(PIXEL *bytearray_ptr, VALUE image);
|
30
|
-
|
31
18
|
#endif
|
@@ -0,0 +1,51 @@
|
|
1
|
+
#include "compix_helpers.h"
|
2
|
+
|
3
|
+
PIXEL* image_to_bytearray(PIXEL *bytearray_ptr, VALUE image){
|
4
|
+
VALUE pixels = rb_funcall(image, rb_intern("pixels"), 0);
|
5
|
+
int x, y;
|
6
|
+
|
7
|
+
int width = NUM2INT(rb_funcall(image, rb_intern("width"), 0));
|
8
|
+
int height = NUM2INT(rb_funcall(image, rb_intern("height"), 0));
|
9
|
+
|
10
|
+
for(y = 0 ; y < height ; y++){
|
11
|
+
for(x = 0 ; x < width ; x++){
|
12
|
+
bytearray_ptr[y * width + x] = NUM2UINT(rb_ary_entry(pixels, y * width + x));
|
13
|
+
}
|
14
|
+
}
|
15
|
+
return bytearray_ptr;
|
16
|
+
}
|
17
|
+
|
18
|
+
int integer_from_hash(VALUE hash, char* key, int default_value, int min_value, int max_value){
|
19
|
+
VALUE val = rb_hash_aref(hash, RB_SYM(key));
|
20
|
+
if( TYPE(val) != T_NIL ) {
|
21
|
+
int c_value = NUM2INT(val);
|
22
|
+
if ( c_value < min_value || c_value > max_value ){
|
23
|
+
rb_raise(rb_eArgError, "argument '%s' has value %d. Allowed range is %d..%d", key, c_value, min_value, max_value);
|
24
|
+
}
|
25
|
+
return c_value;
|
26
|
+
}
|
27
|
+
return default_value;
|
28
|
+
}
|
29
|
+
|
30
|
+
double float_from_hash(VALUE hash, char* key, double default_value, double min_value, double max_value){
|
31
|
+
VALUE val = rb_hash_aref(hash, RB_SYM(key));
|
32
|
+
if( TYPE(val) != T_NIL ) {
|
33
|
+
double c_value = NUM2DBL(val);
|
34
|
+
if ( c_value < min_value || c_value > max_value ){
|
35
|
+
rb_raise(rb_eArgError, "argument '%s' has value %d. Allowed range is %d..%d", key, c_value, min_value, max_value);
|
36
|
+
}
|
37
|
+
return c_value;
|
38
|
+
}
|
39
|
+
return default_value;
|
40
|
+
}
|
41
|
+
|
42
|
+
VALUE initialize_subimage_match_obj(int coord_x, int coord_y, int pixels_compared, int pixels_matched,
|
43
|
+
int subimage_width, int subimage_height, float limit_for_match) {
|
44
|
+
VALUE mCompixModule = rb_const_get(rb_cObject, rb_intern("Compix"));
|
45
|
+
VALUE cSubimageMatch = rb_const_get(mCompixModule, rb_intern("SubimageMatch"));
|
46
|
+
|
47
|
+
VALUE match_obj = rb_funcall(cSubimageMatch, rb_intern("new"), 7, INT2NUM(coord_x), INT2NUM(coord_y),
|
48
|
+
INT2NUM(pixels_compared), INT2NUM(pixels_matched),
|
49
|
+
INT2NUM(subimage_width), INT2NUM(subimage_height), DBL2NUM(limit_for_match));
|
50
|
+
return match_obj;
|
51
|
+
}
|
@@ -0,0 +1,32 @@
|
|
1
|
+
#ifndef COMPIX_HELPERS_H
|
2
|
+
#define COMPIX_HELPERS_H
|
3
|
+
|
4
|
+
#include <ruby.h>
|
5
|
+
#include <stdbool.h>
|
6
|
+
|
7
|
+
|
8
|
+
// Types and macros from OilyPNG for compatibility
|
9
|
+
typedef uint32_t PIXEL; // Pixels use 32 bits unsigned integers
|
10
|
+
typedef unsigned char BYTE; // Bytes use 8 bits unsigned integers
|
11
|
+
#define R_BYTE(pixel) ((BYTE) (((pixel) & (PIXEL) 0xff000000) >> 24))
|
12
|
+
#define G_BYTE(pixel) ((BYTE) (((pixel) & (PIXEL) 0x00ff0000) >> 16))
|
13
|
+
#define B_BYTE(pixel) ((BYTE) (((pixel) & (PIXEL) 0x0000ff00) >> 8))
|
14
|
+
#define A_BYTE(pixel) ((BYTE) (((pixel) & (PIXEL) 0x000000ff)))
|
15
|
+
|
16
|
+
// Symbols for options for method find_subimage
|
17
|
+
#define RB_SYM(string) ID2SYM(rb_intern(string))
|
18
|
+
|
19
|
+
|
20
|
+
|
21
|
+
// The bytearray_ptr should be allocated for the correct size.
|
22
|
+
PIXEL* image_to_bytearray(PIXEL *bytearray_ptr, VALUE image);
|
23
|
+
|
24
|
+
int integer_from_hash(VALUE hash, char* key, int default_value, int min_value, int max_value);
|
25
|
+
|
26
|
+
double float_from_hash(VALUE hash, char* key, double default_value, double min_value, double max_value);
|
27
|
+
|
28
|
+
VALUE initialize_subimage_match_obj(int coord_x, int coord_y, int pixels_compared, int pixels_matched,
|
29
|
+
int subimage_width, int subimage_height, float limit_for_match);
|
30
|
+
|
31
|
+
|
32
|
+
#endif
|
data/lib/compix.rb
CHANGED
@@ -2,5 +2,25 @@ require 'compix.so'
|
|
2
2
|
require 'compix/match.rb'
|
3
3
|
|
4
4
|
module Compix
|
5
|
+
def self.find_all_instances_of_subimage(subimage, image, options={})
|
6
|
+
options[:start_coordinate_x] ||= 0
|
7
|
+
options[:start_coordinate_y] ||= 0
|
8
|
+
matches = []
|
5
9
|
|
10
|
+
subimage_match = self.find_subimage(subimage, image, options)
|
11
|
+
while subimage_match.match?
|
12
|
+
skip = false
|
13
|
+
matches.each do |match|
|
14
|
+
if match.overlaped_by?(subimage_match)
|
15
|
+
skip = true
|
16
|
+
break
|
17
|
+
end
|
18
|
+
end
|
19
|
+
matches << subimage_match unless skip
|
20
|
+
options[:start_coordinate_y] = subimage_match.coordinate_y
|
21
|
+
options[:start_coordinate_x] = subimage_match.coordinate_x + subimage.width
|
22
|
+
subimage_match = self.find_subimage(subimage, image, options)
|
23
|
+
end
|
24
|
+
matches
|
25
|
+
end
|
6
26
|
end
|
data/lib/compix/match.rb
CHANGED
@@ -1,15 +1,19 @@
|
|
1
1
|
require 'chunky_png'
|
2
2
|
|
3
|
+
DEFAULT_PERCENT = 0.85
|
3
4
|
|
4
5
|
class Compix::SubimageMatch
|
5
|
-
attr_reader :coordinate_x, :coordinate_y, :pixels_compared, :pixels_matched
|
6
|
+
attr_reader :coordinate_x, :coordinate_y, :pixels_compared, :pixels_matched, :width, :height
|
6
7
|
|
7
|
-
def initialize(coord_x, coord_y, pixels_compared, pixels_matched)
|
8
|
+
def initialize(coord_x, coord_y, pixels_compared, pixels_matched, width, height, limit_for_match=DEFAULT_PERCENT)
|
8
9
|
raise ArgumentError.new("Matched more pixels ('#{pixels_matched}') than compared ('#{pixels_compared}')") if pixels_compared < pixels_matched
|
9
10
|
@coordinate_x = coord_x
|
10
11
|
@coordinate_y = coord_y
|
11
12
|
@pixels_compared = pixels_compared
|
12
13
|
@pixels_matched = pixels_matched
|
14
|
+
@width = width
|
15
|
+
@height = height
|
16
|
+
@match = limit_for_match <= self.match_percentage
|
13
17
|
end
|
14
18
|
|
15
19
|
def match_percentage
|
@@ -17,11 +21,29 @@ class Compix::SubimageMatch
|
|
17
21
|
pixels_matched.to_f / pixels_compared
|
18
22
|
end
|
19
23
|
|
24
|
+
def match?
|
25
|
+
@match
|
26
|
+
end
|
27
|
+
|
20
28
|
def eql?(other)
|
21
29
|
other.class.eql?(self.class) && other.state.eql?(self.state)
|
22
30
|
end
|
23
31
|
|
32
|
+
def overlaped_by?(other)
|
33
|
+
return false if other.coordinate_x + other.width <= @coordinate_x
|
34
|
+
return false if other.coordinate_x >= @coordinate_x + @width
|
35
|
+
return false if other.coordinate_y + other.height <= @coordinate_y
|
36
|
+
return false if other.coordinate_y >= @coordinate_y + @height
|
37
|
+
true
|
38
|
+
end
|
39
|
+
|
24
40
|
def state
|
25
41
|
[@coordinate_x, @coordinate_y, @pixels_compared, @pixels_matched]
|
26
42
|
end
|
43
|
+
|
44
|
+
def coordinate_middle
|
45
|
+
x = @coordinate_x + @width / 2
|
46
|
+
y = @coordinate_y + @height / 2
|
47
|
+
return [x, y]
|
48
|
+
end
|
27
49
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: compix
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jon Appelberg
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-10-
|
11
|
+
date: 2014-10-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake-compiler
|
@@ -75,6 +75,8 @@ extra_rdoc_files: []
|
|
75
75
|
files:
|
76
76
|
- ext/compix/compix.c
|
77
77
|
- ext/compix/compix.h
|
78
|
+
- ext/compix/compix_helpers.c
|
79
|
+
- ext/compix/compix_helpers.h
|
78
80
|
- ext/compix/extconf.rb
|
79
81
|
- lib/compix.rb
|
80
82
|
- lib/compix/match.rb
|