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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d31400ba7b637660ef09a34d8c45228d25811274
4
- data.tar.gz: 2c5589a1b5da50cd87e2d4ad50a908168139acf7
3
+ metadata.gz: 573a0eea05badf4bd1964736361513caeed36ecb
4
+ data.tar.gz: 952fc5643ce5a5fd16b9f45d540f7bb101c14ca0
5
5
  SHA512:
6
- metadata.gz: 6676275970f1c794242b386f74f0fc5fd419a96800e758db97d57ce7b79741092638098a9a15a36d683d3f2ebae9d9f589ebb23ebffa0e007db491e30ea13b04
7
- data.tar.gz: 07740fd33ca945ab6c89c7d522ff284561823b3701696a62b45c7806c2b49420e4693715f701ccb34db94cb5cc7cd1960ee2650599139e9309e68a4899a69a9f
6
+ metadata.gz: a0fd67bdf4fbfb99f753aed312fea832dffe4fcb3713565b54cc2337ef115440226a8c5cba4e39e1138b39de9e277f3b04c56446198af423076a06910355d700
7
+ data.tar.gz: 98ec2b5321a0e51d7476db720fab5965afe10ffe691325f937abab55454b8f7dafeb5aed224594f671f7fc71f336ff2e778c47d41744c8d84228903132f033e7
@@ -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, 3);
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 thres, int bigXoffset, int bigYoffset,
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, thres)){
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
- PIXEL* image_to_bytearray(PIXEL *bytearray_ptr, VALUE image){
59
- VALUE pixels = rb_funcall(image, rb_intern("pixels"), 0);
60
- int x, y;
61
-
62
- int width = NUM2INT(rb_funcall(image, rb_intern("width"), 0));
63
- int height = NUM2INT(rb_funcall(image, rb_intern("height"), 0));
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
- for(y = 0 ; y < height ; y++){
66
- for(x = 0 ; x < width ; x++){
67
- bytearray_ptr[y * width + x] = NUM2UINT(rb_ary_entry(pixels, y * width + x));
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(bigimage, rb_intern("width"), 0));
79
- int ssheight = NUM2INT(rb_funcall(bigimage, rb_intern("height"), 0));
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
- //int xLeftLimit = NUM2INT(rb_ary_entry(minCoord, 0));
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, bigimage);
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, thres, x, y,
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
- }
@@ -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(VALUE self, VALUE subimage, VALUE bigimage, VALUE threshold);
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
@@ -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
@@ -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.1.1
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-29 00:00:00.000000000 Z
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