aj3423
aj3423

Reputation: 2561

search for a small image in a big one

I'm working on search a gray-scaled image from a big one.

Here's what I've done so far, simply search pixel by pixel from left to right and top to bottom, it's gray-scaled so I use bool as the data type (1==black 0==white).

#include <iostream>
using namespace std;

template <int WIDTH, int HEIGHT>
struct array {
    bool data[WIDTH][HEIGHT];
    int width() { return WIDTH; }
    int height() { return HEIGHT; }

    void random_fill() {
        for(int row=0; row<HEIGHT; row++) {
            for(int col=0; col<WIDTH; col++) {
                data[row][col] = (row*col+col*col) % 3 == 0 ? 1 : 0;
            }
        }
    }
    void display() {
        cout << "array content:" << endl;
        for(int row=0; row<HEIGHT; row++) {
            for(int col=0; col<WIDTH; col++) {
                cout << data[row][col] << " ";
            }
            cout << endl;
        }
    }
    void operator=(bool _data[WIDTH][HEIGHT]) {
        memcpy(data, _data, WIDTH*HEIGHT);
    }
};

struct point {
    int x;
    int y;
};

// test if a sub-rect of a big_rect matches a small rect
template <typename big_t, typename small_t>
bool rect_match(big_t& big_arr, int x_offset, int y_offset, small_t& small_arr) {
    int w = small_arr.width(),
        h = small_arr.height();
    for(int row=0; row<h; row++) {
        for(int col=0; col<w; col++) {
            if(big_arr.data[row+y_offset][col+x_offset] != small_arr.data[row][col])
                return false;
        }
    }
    return true;
}

// search for a small_rect in a big_rect
template <typename big_t, typename small_t>
point search(big_t& big_arr, small_t& small_arr) {
    point pt;
    for(int row=0; row<big_arr.height()-small_arr.height(); row++) {
        for(int col=0; col<big_arr.width()-small_arr.width(); col++) {
            if(rect_match(big_arr, col, row, small_arr)) {
                pt.x = col;
                pt.y = row;
                return pt;
            }
        }
    }

    pt.x = pt.y = -1;
    return pt;
}

int main() {
    array<10, 10> big_arr;
    big_arr.random_fill(); // fill the sample image with some "random" color
    big_arr.display(); 

    array<3, 3> small_arr;
    bool data[3][3] = {{1,0,1},{0,0,1},{0,1,1}};
    small_arr = data;
    small_arr.display(); 

    point pt = search(big_arr, small_arr);
    cout << "pt: (" << pt.x << ", " << pt.y << ")" << endl;

}

I'm looking for some better algorithm that with better performance.

Any advice?

Thanks.

Upvotes: 2

Views: 201

Answers (1)

user2249683
user2249683

Reputation:

You might interpret the larger image as a string of bytes for applying a string-search algorithm like the 'Boyer–Moore string search algorithm' (http://en.wikipedia.org/wiki/Boyer%E2%80%93Moore_string_search_algorithm) to find the first line of the smaller image. After finding that line, you match the following lines.

However, if the smaller image is not found (not aligned to a byte boundary in the larger image), you have to repeat the search using a shifted smaller image (temporary ignoring the first and last byte), until you find a match or no further shift is plausible.

Upvotes: 2

Related Questions