compix 0.1.1 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|