LINUX.ORG.RU

Сравнение двух BufferedImage, нужна помощь

 , ,


0

2

Ниже рабочий код. Но работает очень медленно.

Что тут можно оптимизировать для ускорения работы?

Скан может быть 1368 на 768 точек

Образец для сравнения 20 на 20 точек

package comparator;

import java.awt.image.BufferedImage;
import java.io.File;

import javax.imageio.ImageIO;

public class RGBComparator 
{

    /**
     * @param args
     */
    public static void main(String[] args) 
    {
        
        try
        {
        
            log("Start");
            long time1 = System.currentTimeMillis();
            
            BufferedImage img1 = ImageIO.read(new File("res/guild.png"));
            
            BufferedImage img2 = ImageIO.read(new File("res/scan1.png"));
            
            int[][][] rgb = new int[256][256][256];
            
            int w1 = img1.getWidth();
            int h1 = img1.getHeight();
            
            for(int i=0;i<w1; i++)
            {
                for(int j=0; j<h1; j++)
                {
                    int[] rgb1 = img1.getRaster().getPixel(i, j, new int[3]);
                    
                    rgb[rgb1[0]][rgb1[1]][rgb1[2]] ++;
                    
                    
                }
            }
            
            
            
            
            
            int w2 = img2.getWidth();
            int h2 = img2.getHeight();
            
            for(int x=0; x<(w2-w1)+1;x++)
            {
                for(int y=0;y<(h2-h1)+1;y++)
                {
                    
                    //log("...");
                    
                    int errors = 0;
                    
                    int[][][] c_rgb = copyRGB(rgb);
                    
                    for(int i=0;i<w1; i++)
                    {
                        for(int j=0; j<h1; j++)
                        {
                            
                                int[] rgb2 = img2.getRaster().getPixel((x+i), (y+j), new int[3]);
                                
                                int v = c_rgb[rgb2[0]][rgb2[1]][rgb2[2]];
                                
                                if( v == 0) { errors++; continue; }
                                
                                c_rgb[rgb2[0]][rgb2[1]][rgb2[2]] --;
                        
                        }
                    }
                    
                    int zcounter=0;
                    int pcounter=0;
                    int mcounter=0;
                    
                    for(int r=0;r<256;r++)
                    {
                        for(int g=0;g<256;g++)
                        {
                            for(int b=0;b<256;b++)
                            {
                                if(c_rgb[r][g][b]>0) pcounter++;
                                else if(c_rgb[r][g][b]<0) mcounter++;
                                else zcounter++;
                            }
                        }
                    }
                    
                    
                    
                    if(pcounter < 10 && mcounter < 10)
                    {
                        log("For ["+x+","+y+"]");
                        log("errors= "+errors);
                        log("pcounter= "+pcounter);
                        log("zcounter= "+zcounter);
                        log("mcounter= "+mcounter);
                        
                    }
                    
                    
                    
                }
            }
            
            long time2 = System.currentTimeMillis();
            log("Finish");
            log("ET(ms)= "+(time2-time1));
        
        
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }

    }

    private static int[][][] copyRGB(int[][][] rgb) 
    {
        int[][][] res = new int[256][256][256];
    
        for(int r=0;r<256;r++)
        {
            for(int g=0;g<256;g++)
            {
                for(int b=0;b<256;b++)
                {
                    res[r][g][b] = rgb[r][g][b];
                }
            }
        }
        
        return res;
    }

    private static void log(String s) 
    {
        System.out.println(s);
        
    }

}

int[][][] res = new int[256][256][256];

Это 256^3 * sizeof(int)? Может достаточно 256*3*sizeof(unsigned char)?
А лучше сделать 256*4*sizeof(unsigned char) - так по идее доступ будет быстрее из-за выравнивания по границе слова и более редкого cache miss.

Ну и вложенные циклы зло. Да еще и в таком количестве.

p.s. Впрочем, что там ява сделает на выходе, одному компилятору известно.

andreyu ★★★★★
()
Ответ на: комментарий от andreyu

Оптимизировал вот до чего. Стало быстрее! Но хотелось бы еще более ускорить.

	public static void main(String[] args) 
	{
		
		try
		{
		
			log("Start");
			long time1 = System.currentTimeMillis();
			
			BufferedImage img1 = ImageIO.read(new File("res/guild.png"));
			
			BufferedImage img2 = ImageIO.read(new File("res/scan.png"));
			
			int[][][] rgb = new int[256][256][256];
			
			int w1 = img1.getWidth();
			int h1 = img1.getHeight();
			
			for(int i=0;i<w1; i++)
			{
				for(int j=0; j<h1; j++)
				{
					int[] rgb1 = img1.getRaster().getPixel(i, j, new int[3]);
					
					rgb[rgb1[0]][rgb1[1]][rgb1[2]] ++;
					
					
				}
			}
			
			
			
			
			
			int w2 = img2.getWidth();
			int h2 = img2.getHeight();
			
			int min_errors = w2*h2;
			Point min_point = null;
			
			for(int x=0; x<(w2-w1)+1;x++)
			{
				for(int y=0;y<(h2-h1)+1;y++)
				{
					
					//log("...");
					
					int errors = 0;
					int zcounter=0;
					
					//int[][][] c_rgb = copyRGB(rgb);
					
					for(int i=0;i<w1; i++)
					{
						for(int j=0; j<h1; j++)
						{
							
								int[] rgb2 = img2.getRaster().getPixel((x+i), (y+j), new int[3]);
								
								if( rgb[rgb2[0]][rgb2[1]][rgb2[2]] == 0) errors++;
								else zcounter++;
								
								//if( v == 0) { errors++; continue; }
								
								//c_rgb[rgb2[0]][rgb2[1]][rgb2[2]] --;
						
						}
					}
				
					/********
					int zcounter=0;
					int pcounter=0;
					int mcounter=0;
					
					for(int r=0;r<256;r++)
					{
						for(int g=0;g<256;g++)
						{
							for(int b=0;b<256;b++)
							{
								if(c_rgb[r][g][b]>0) pcounter++;
								else if(c_rgb[r][g][b]<0) mcounter++;
								else zcounter++;
							}
						}
					}
					
					*******/
					
					
					
					if(zcounter > errors)
					{
						
						if(min_errors > errors)
						{
							min_point = new Point(x,y);
							min_errors = errors;
						}
					}
					
					
					
				}
			}
			
			long time2 = System.currentTimeMillis();
			if(min_point != null)
			{
				log("Found at: ["+min_point.x+","+min_point.y+"] with errors: "+min_errors);
			}
			
			log("Finish");
			log("ET(ms)= "+(time2-time1));
		
		
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}

	}

Oleg_Dorozhko
() автор топика
Ответ на: комментарий от andreyu

Сейчас поэкспериментирую с выравниванием. Спасибо!

Oleg_Dorozhko
() автор топика

Используй метод BufferedImage.getRGB вместо getRaster().getPixel. Считывай из BufferedImage сразу всю строку в массив int-ов и дальше с этим работай.

В твоём алгоритме трёхмерный массив лучше заменить на одномерный из 256^3 элементов. Собственно getRGB тебе будет выдавать массив готовых индексов (только 4-й байт занули, если там альфа-канал есть, чтобы он не мешался).

Если всё сделаешь правильно, будет работать моментально.

Legioner ★★★★★
()
Ответ на: комментарий от Legioner

В твоём алгоритме трёхмерный массив лучше заменить на одномерный из 256^3 элементов.

Зачем ему 256*256*256 элементов? Может 256*3 (а лучше 256*4) использовать?

andreyu ★★★★★
()
Ответ на: комментарий от andreyu

Зачем ему 256*256*256 элементов?

Потому что он считает количество пикселов каждого цвета.

Может 256*3 (а лучше 256*4) использовать?

Может быть лучше по памяти и сравнимо по скорости использовать что-то вроде хеш-таблицы, если в изображении мало цветов. Если много - скорее всего будет сильно хуже по скорости. На разовую обработку изображения выделить 64 мегабайта по-моему не критично, хотя зависит от задачи.

Legioner ★★★★★
()
Ответ на: комментарий от Legioner

на одномерный из 256^3 элементов

Ну я не понимаю, как это сделать.

int[][][] rgb это трехмерная матрица

В ней я считаю количество цветов.

Цвет точки x,y падает в нее, инкрементируясь.

Получается трехмерная матрица частот цветов.

Как вот этот кусок превратить в такой же но с одномерным массивом?


int[][][] rgb = new int[256][256][256];
			
			int w1 = img1.getWidth();
			int h1 = img1.getHeight();
			
			for(int i=0;i<w1; i++)
			{
				for(int j=0; j<h1; j++)
				{
					int[] rgb1 = img1.getRaster().getPixel(i, j, new int[3]);
					
					rgb[rgb1[0]][rgb1[1]][rgb1[2]] ++;
					
					
				}
			}
			
Oleg_Dorozhko
() автор топика
Ответ на: комментарий от Legioner

Потому что он считает количество пикселов каждого цвета.

Вот оно что, Михалыч. Я не смотрел алгоритм.

andreyu ★★★★★
()
Ответ на: комментарий от Oleg_Dorozhko

Получается трехмерная матрица частот цветов.

Посыпаю голову пеплом, я не уловил суть алгоритма.

int[] rgb1 = img1.getRaster().getPixel(i, j, new int[3]);

А выделение памяти в цикле - это нормально?

Что делает getRaster()? Вычисляется каждую итерацию?

Сдается мне, что в данном случае лучше выделить линейный массив RGBX (или RGBA), заполнить его предварительно нужными данными из битмапа и двигаться по нему смещаясь на слово.

andreyu ★★★★★
()
Ответ на: комментарий от Legioner

Я считал, что getRGB медленнее работает, чем getRaster().getPixel

getRGB возвращает какой-то страшный int

И он бы мне подошел, если бы я знал как объявить совершенно дикий массив с отрицательными индексами.

Или можно сделать по другому?

Oleg_Dorozhko
() автор топика
Ответ на: комментарий от Oleg_Dorozhko

Мне нужно максимально быстрым образом посчитать частоты цветов образца. Не понимаю, как с одномерным массивом это можно решить.

Oleg_Dorozhko
() автор топика
Ответ на: комментарий от Oleg_Dorozhko

С явой не помогу, но псевдокод такой:

int w1 = img1.getWidth();
int h1 = img1.getHeight();

unsigned pixel_size = 4; // для RGBX или 3 для RGB
unsigned size = w1 * h1 * pixel_size;
unsigned char* rgbx_bitmap = new unsigned char[size];

fillRGBX(...);

for(unsigned i = 0; i < size; i += pixel_size)
{
   unsigned r = rgbx_bitmap[i + 0];
   unsigned g = rgbx_bitmap[i + 1];
   unsigned b = rgbx_bitmap[i + 2];

   rgb[r][g][b]++;
}

andreyu ★★★★★
()
Ответ на: комментарий от Oleg_Dorozhko

Не понимаю, как с одномерным массивом это можно решить.

Считать индекс в одномерном массиве самостоятельно. Как пример:

int a[10][10];
a[5][5] = value;
равнозначен такому коду:
int a[100];
a[5 * 10 + 5] = value;

andreyu ★★★★★
()
Ответ на: комментарий от andreyu

Вот что получилось:


package comparator;

import java.awt.Color;
import java.awt.Point;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

public class RGBComparator2 
{

	/**
	 * @param args
	 */
	public static void main(String[] args) 
	{
		
		try
		{
		
			//testColors();
			
			log("Start");
			long time1 = System.currentTimeMillis();
			
			BufferedImage img1 = ImageIO.read(new File("res/guild.png"));
			BufferedImage img2  = ImageIO.read(new File("res/scan.png"));
			
			compareImages(img1, img2);
			
			long time2 = System.currentTimeMillis();
			log("Finish");
			log("ET(ms)= "+(time2-time1));
		
		
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}

	}

	private static void testColors() 
	{
		Color c = Color.WHITE;
		log(""+c.getRGB());
		int rgb_rgb=c.getRGB();
		int r = ((rgb_rgb >> 0 * 8) & 255);
		int g = ((rgb_rgb >> 1 * 8) & 255);
		int b = ((rgb_rgb >> 2 * 8) & 255);
		Color c1 = new Color(r,g,b);
		log("r="+r);
		log("g="+g);
		log("b="+b);
		log(""+c1.getRGB());
	}

	
	
	private static void compareImages(BufferedImage img1, BufferedImage img2) throws IOException 
	{
		
		//ET(ms)= 8812
		
		int[] rgb = new int[256*256*256];
		
		for(int i=0;i<256*256*256;i++) rgb[i]=0;
				
		
		int w1 = img1.getWidth();
		int h1 = img1.getHeight();
		
		for(int i=0;i<w1; i++)
		{
			for(int j=0; j<h1; j++)
			{
				int[] rgb1 = img1.getRaster().getPixel(i, j, new int[3]);
				
				
				rgb[256*256*rgb1[0] + 256*rgb1[1] + rgb1[2]] ++;
				
				
			}
		}
		
		
		
		
		
		int w2 = img2.getWidth();
		int h2 = img2.getHeight();
		
		int max_cmp = 0;
		Point min_point = null;
		
		for(int x=0; x<(w2-w1)+1;x++)
		{
			for(int y=0;y<(h2-h1)+1;y++)
			{
				
				//log("...");
				
				
				int zcounter=0;
				
				 
				
				for(int i=0;i<w1; i++)
				{
					for(int j=0; j<h1; j++)
					{
						
							int[] rgb2 = img2.getRaster().getPixel((x+i), (y+j), new int[3]);
							
							
							if( rgb[256*256*rgb2[0] + 256*rgb2[1] + rgb2[2]] != 0) zcounter++;
							
							
					
					}
				}
			
			

				
				
				
				
				if(max_cmp < zcounter)
				{
						max_cmp = zcounter;
						min_point = new Point(x,y);
		
					
				}
				
				
				
				
				
			}
		}
		
		
		if(min_point != null)
		{
			log("Found at: ["+min_point.x+","+min_point.y+"] with max_cmp: "+max_cmp);
		}
		
	}

	
	private static void log(String s) 
	{
		System.out.println(s);
		
	}
	
	

}

Oleg_Dorozhko
() автор топика
Ответ на: комментарий от Oleg_Dorozhko

Ну я не понимаю, как это сделать.

int[][][] rgb = new int[256][256][256];
int[] rgb = new int[256 * 256 * 256];

rgb[r][g][b] = 1;
rgb1[r * 256 * 256 + g * 256 + b] = 1

Более того, getRGB возвращает тебе цвета, уже «закодированные» таким образом - 256 * 256 * r + 256 * g + b. Т.е. один 4-байтовый int содержит в себе информацию о трёх цветах (на самом деле ещё и о четвёртом - о прозрачности этого пиксела).

Вот аналог кода для getRGB и одномерного массива.

        int[] rgb = new int[256 * 256 * 256];

        // чтобы память постоянно не выделять, выделяем один раз на всю строку img1
        int[] img1Row = new int[img1.getWidth()];

        // меняем циклы местами, так быстрее
        for (int row = 0; row < img1.getHeight(); ++row) {
            // получаем все пиксели данной строки
            img1.getRGB(0, row, img1.getWidth(), 1, img1Row, 0, img1.getWidth());
            // теперь перебираем их
            for (int col = 0; col < img1.getWidth(); ++col) {
                // получаем четвёрку (прозрачность, красный, зеленый, синий)
                int pixelARGB = img1Row[col];
                // удаляем прозрачность, она нам не нужна
                int pixelRGB = pixelARGB & 0x00ffffff;
                // теперь считаем статистику
                rgb[pixelRGB] += 1;
            }
        }

Также используй System.arrayсopy для копирования того массива. Это будет быстрее.

Ну а вообще у тебя по-любому будет тормозить. Копировать 64 мегабайта памяти миллионы раз это очень медленно. Тебе надо алгоритм изменить. Какие у тебя типичные размеры сравниваемых картинок?

Legioner ★★★★★
()
Ответ на: комментарий от Carb_blog4

Он идёт по большой картинке и в цикле 1348x748 пытается «приложить» маленькую картинку к большой в соответствующем месте и по статистике цветов получает некую характеристику «схожести» этой маленькой картинки с данным участком большой.

Legioner ★★★★★
()

Что тут можно оптимизировать для ускорения работы?

Воспользоваться opencv?

ya-betmen ★★★★★
()

Вот тебе пример алгоритма, который может сработать в твоём случае. Код сильно усложнится, но работать будет очень быстро в сравнение с твоим вариантом.

Во-первых для хранения статистики цветов тебе надо помимо хранения массива в 16 миллионов элементов ещё хранить просто список ненулевых цветов. Т.е. у тебя на картинке например 1000 разных цветов встречается. Это значит, что в массиве rgb у тебя будет 1000 ненулевых элементов, а остальные нулевые. И когда ты его будешь сравнивать с другим массивом, ты 99.9% времени будешь крутить вхолостую. А если ты хранишь конкретный список ненулевых элементов, то тебе надо будет пройтись только по ним. Весь этот функционал разумно вынести в класс. ColorStatistic какой-нибудь.

Во-вторых ты считаешь c_rgb каждый раз заново для каждого участка второй картинки. Это можно сильно оптимизировать. Примерно так: сначала считаешь исходный вариант для x = 0, y = 0 (аналогично rgb, просто считаешь число разных цветов). После этого ты движешься по x вправо до img2.width - img1.width. На каждой итерации ты не пересчитываешь этот c_rgb заново, а просто прибавляешь статистику для столбца шириной в 1 пиксель справа и вычитаешь статистику для столбца шириной в 1 пиксель слева. Таким образом у тебя будет верная статистика, но для её подсчёта ты тратишь не width * height операций, а 2 * height операций. В конце строки сдвигаешься на один пиксель вниз и аналогично прибавляешь статистику для строки высотой в один пиксель, которая снизу и вычитаешь статистику для строки высотой в один пиксель сверху. И потом движешься уже назад, влево. И так «змейкой» обходишь всю картинку img2.

Пока обходишь, на каждой итерации тебе надо сравнивать статистику для первой картинки, которую ты один раз подсчитал и не трогаешь и статистику для части второй картинки, которую ты в данный момент считаешь. Собственно для этого ты итерируешься не 256 * 256 * 256 раз, а только по тем цветам, которые ты до этого запоминал, как ненулевые хотя бы в одной картинке.

Да, что касается BufferedImage. Рекомендую просто сделать массив двумерный конкретно для картинки и перед началом работы «выгрузить» всю картинку в этот простой массив. BufferedImage достаточно тормозной класс, проще и быстрей работать с простым массивом.

Legioner ★★★★★
()
Последнее исправление: Legioner (всего исправлений: 1)
Ответ на: комментарий от Oleg_Dorozhko

Есть метод

byte[] pixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
Это фактически прямой доступ, быстрее имно не бывает. Он возвращает массив компонентов. т.е. pixel[0] - (алфа канал первого пиксела, или голубой первого пиксела, если канала нет), pixel[1] - (голубой первого пиксела, если альфа канал, зелёный ежель альфы нет). и т.д.

Наличие альфы можно проверить

boolean hasAlphaChannel = image.getAlphaRaster() != null;

по мелочи

Массивы заполняются нулями

for(int i=0;i<256*256*256;i++) rgb=0; не нужно.

vtVitus ★★★★★
()
Последнее исправление: vtVitus (всего исправлений: 1)
Ответ на: комментарий от Oleg_Dorozhko

ещё по мелочи getPixel используют так

int[] rgb2 = null;
for(int i=0;i<w1; i++) {
  for(int j=0; j<h1; j++) {
    rgb2 = img2.getRaster().getPixel((x+i), (y+j), rgb2);
    if( rgb[256*256*rgb2[0] + 256*rgb2[1] + rgb2[2]] != 0)
      zcounter++;
  }
}
vtVitus ★★★★★
()
Ответ на: комментарий от vtVitus

Я дошел до того, что нужно сравнить два массива int[256]

Понятия не имею как это сделать

[11, 34, 0, 15] и [12, 35, 1, 17] примерно равны

а

[11, 34, 0, 15] и [112, 35, 1, 15] уже не равны

а

[11, 34, 0, 15] и [112, 35, 100, 15] не равны

Oleg_Dorozhko
() автор топика
Ответ на: комментарий от Oleg_Dorozhko

Вот последняя версия.

Может подскажете еще какие-нибудь критерии сравнения?


package comparator;

import java.awt.Color;
import java.awt.Point;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;

public class RGBComparator
{
	public static int DIFFERENCE = 1;
	public static double PROBABILITY = 0.8;
	
	public static boolean equal(int n1, int n2)
	{
		int dif=0;
		if (n1>n2) dif = n1-n2;
		else if (n2>n1) dif = n2-n1;
		 
		return (dif < DIFFERENCE  );
	}
	/**
	 * @param args
	 */
	public static void main(String[] args) 
	{
		
		try
		{
		
			//testColors();
			
			log("Start");
			long time1 = System.currentTimeMillis();
			
			BufferedImage img1 = ImageIO.read(new File("res/send_to_klan.png"));
			BufferedImage img2  = ImageIO.read(new File("res/scan5.png"));
			
//			BufferedImage img1 = ImageIO.read(new File("res/guild.png"));
//			BufferedImage img2  = ImageIO.read(new File("res/scan5.png"));
			
			compareImages(img1, img2);
			
			long time2 = System.currentTimeMillis();
			log("Finish");
			log("ET(ms)= "+(time2-time1));
		
		
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}

	}

	private static void testColors() 
	{
		Color c = Color.WHITE;
		log(""+c.getRGB());
		int rgb_rgb=c.getRGB();
		int r = ((rgb_rgb >> 0 * 8) & 255);
		int g = ((rgb_rgb >> 1 * 8) & 255);
		int b = ((rgb_rgb >> 2 * 8) & 255);
		Color c1 = new Color(r,g,b);
		log("r="+r);
		log("g="+g);
		log("b="+b);
		log(""+c1.getRGB());
	}

	
	
	private static Point compareImages(BufferedImage img1, BufferedImage scan) throws IOException 
	{
		
		int w1 = img1.getWidth();
		int h1 = img1.getHeight();
		
		int[] r = new int[256];
		int[] g = new int[256];
		int[] b = new int[256];
		
		//for(int i=0;i<256;i++) { r[i]=0; g[i]=0; b[i]=0; }

		
		for(int i=0;i<w1; i++)
		{
			for(int j=0; j<h1; j++)
			{
				int[] rgb = img1.getRaster().getPixel(i, j, new int[3]);
								
				r[rgb[0]] ++;
				g[rgb[1]] ++;
				b[rgb[2]] ++;
				
			}
		}
		
		int psum = 0;
		for(int i=0;i<255;i++) 
		{ 
		
			if(r[i] == 0 && g[i] == 0 && b[i] == 0) continue;
			
			psum++;
		}
		
		psum*=3;
		
		log("psum="+psum);
		
		int w2 = scan.getWidth();
		int h2 = scan.getHeight();
				 
		int max_value_cmp_counter = 0;
		Point target_point = null;
		
		for(int x=0; x<(w2-w1)+1;x++)
		{
			for(int y=0;y<(h2-h1)+1;y++)
			{
				
				//log("...");
				
				int[] r_scan = new int[256];
				int[] g_scan = new int[256];
				int[] b_scan = new int[256];
				
				
			//	for(int i=0;i<256;i++) { r_scan[i]=0; g_scan[i]=0; b_scan[i]=0; }
				
				
				
				for(int i=0;i<w1; i++)
				{
					for(int j=0; j<h1; j++)
					{
						
							int[] rgb = scan.getRaster().getPixel((x+i), (y+j), new int[3]);
							
							r_scan[rgb[0]] ++;
							g_scan[rgb[1]] ++;
							b_scan[rgb[2]] ++;
					
					}
				}
				
			//вот здесь нужно сравнение r[i] ? r_scan[i]
				
				int sumr = 0;
				int sumg = 0;
				int sumb = 0;
				int cmp_counter=0;
				for(int i=0;i<255;i++) 
				{ 
				
	//				 if(equal(r[i],r_scan[i])) sumr++;
	//				 if(equal(g[i],g_scan[i])) sumg++;
	//				 if(equal(b[i],b_scan[i])) sumb++;
					
					if(r[i] == 0 && g[i] == 0 && b[i] == 0) continue;
					
					if(r_scan[i] == 0 && g_scan[i] == 0 && b_scan[i] == 0) continue;
					
					
					if(r[i]==r_scan[i]) cmp_counter++;//sumr+=r_scan[i]; //else sumr--;
					if(g[i]==g_scan[i]) cmp_counter++;//sumg+=g_scan[i]; //else sumg--;
					if(b[i]==b_scan[i]) cmp_counter++; //sumb+=b_scan[i]; //else sumb--;
					
				}
				
				
				if(max_value_cmp_counter < cmp_counter ) //&& mv <= psum + psum * (1 - PROBABILITY))
				{
				
					max_value_cmp_counter = cmp_counter;
					target_point = new Point(x,y);
					
				}
			
				
			}
		}
		
		
		if(target_point != null)
		{
		 	if( max_value_cmp_counter > psum * PROBABILITY )
			{
				log("Found at: ["+target_point.x+","+target_point.y+"] with psum: "+psum+" and max_value_cmp_counter: "+max_value_cmp_counter);
				log("Rel: "+(max_value_cmp_counter*100)/psum+"%");
				return target_point;
			}
		 	else 
		 	{
		 		log("NOT FOUND at: ["+target_point.x+","+target_point.y+"] with psum: "+psum+" and max_value_cmp_counter: "+max_value_cmp_counter);
				log("Rel: "+(max_value_cmp_counter*100)/psum+"%");
				
		 	}
		}
		
		return null;
	}

	

	
	
	private static void log(String s) 
	{
		System.out.println(s);
		
	}
	
	

}

Oleg_Dorozhko
() автор топика
Ответ на: комментарий от Oleg_Dorozhko

Я разрабатываю контекстно-зависимый эмулятор действий пользователя (плагины для любых программ и их комбинаций) с логическим командным языком.

Вот как выглядит скрипт для эмулятора:


find strawberry => put_to_basket

где  strawberry это скан клубники, а  put_to_basket скрипт сбора клубники в корзину

Распознавание графического контекста на скане является его важнейшей частью и самой критичной ко времени выполнения.

Еще рекурсию нужно развернуть.

Сейчас возможно сделать так: если имя основного скрипта main, то скрипт:


find strawberry => put_to_basket !=> ready

run script main

будет вызывать себя рекурсивно, пока вся клубника не будет собрана или не кончится память

Так вот - не сделано, чтобы эта конструкция исполнялась эмулятором не как рекурсия , а как два цикла

В случае двух циклов память вроде не теряется.

А вообще вот ссылка на проект - исходники и jar эмулятора

Только все еще сырое

Oleg_Dorozhko
() автор топика
Ответ на: комментарий от Oleg_Dorozhko

И еще - я безработный :(

Может кто-нибудь порекомендовать?

Говорят, за это денег дают.

Oleg_Dorozhko
() автор топика
Ответ на: комментарий от Oleg_Dorozhko

То, что бросилось в глаза:

int r = ((rgb_rgb >> 0 * 8) & 255);
int g = ((rgb_rgb >> 1 * 8) & 255);
int b = ((rgb_rgb >> 2 * 8) & 255);

1. Приоритет операции * выше, чем операции сдвига.
2. Сдвиг нужно делать не на 1 и 2 бита, а на 8 и 16 бит.

andreyu ★★★★★
()
Последнее исправление: andreyu (всего исправлений: 1)

Почему ты просто не сравниваешь 2 изображения, а используешь промежуточный массив? Ну я имею ввиду типа такого:

int x, y, errors;
for (x = 0; x < width; x++) {
    for (y = 0; y < height; y++) {
        if (image1.getPixel(x, y) != image2.getPixel(x, y)) {
            errors++;
        }
    }
}

Возможно, конечно, в Java так оптимальнее, но мне твой код кажется очень странным.

А вообще по идее самое хорошее преобразовать изображения в массив байт и сравнивать уже их стандартными функциями сравнения массивов.

KivApple ★★★★★
()
Ответ на: комментарий от andreyu

Это не используется, но все равно спасибо

Т.е. так правильно будет?


int r = ((rgb_rgb >> 0 * 8) & 255);
int g = ((rgb_rgb >> 8 * 8) & 255);
int b = ((rgb_rgb >> 16 * 8) & 255);

Oleg_Dorozhko
() автор топика
Ответ на: комментарий от KivApple

Если изображения векторные их уже не сравнить попиксельно. Они «плывут» - слегка не тот цвет слегка не в том месте. Визуально все в порядке, а на уровне пикселей не совпадения постоянные.

Я распознаю flash анимацию - делаю бота для браузерной игры с помощью скриптов для эмулятора.

Бот и есть набор скриптов, исполняемый интерпретатором командного языка.

Oleg_Dorozhko
() автор топика
Ответ на: комментарий от Legioner

Он идёт по большой картинке и в цикле 1348x748 пытается «приложить» маленькую картинку к большой в соответствующем месте

Для этого не надо обходить «большую картинку».

и по статистике цветов получает некую характеристику «схожести» этой маленькой картинки с данным участком большой.

Как получить схожесть? Разность между цветами маленькой и кусочке большой меньше какого-то коэффициента?

int[][][] rgb = new int[256][256][256];

Я вообще не вижу логики в этой конструкции. Я не понимаю как работает мозг жабиста.

Carb_blog4
()
Ответ на: комментарий от Oleg_Dorozhko

Меня интересует getRGB

Ты не понял, что я написал. Все методы (getRGB, getPixel и т.п.) работают над массивом, который получается ((DataBufferByte) image.getRaster().getDataBuffer()).getData();

Если ты хочешь сделать быстро, ты _должен_ работать с ним. Если ты хочешь сделать абы как, то причём тут оптимизация.

Если у тебя проблема с алгоритмом, то нет внятной постановки, что именно ты хочешь сравнить и для чего. И алгоритмы работы с изображением хорошо описаны в книжках, искать подсказки на тонне форумов бесполезно.

vtVitus ★★★★★
()

работает очень медленно

это естестветственно - это жаба

quest ★★★★
()
Ответ на: комментарий от Carb_blog4

15 секунд для поиска картинки 20 на 20 на результате robot.createScreenCapture()

Oleg_Dorozhko
() автор топика
Ответ на: комментарий от vtVitus

Спасибо, прямо сейчас изучу влияние на скорость обработки

((DataBufferByte) image.getRaster().getDataBuffer()).getData();

Oleg_Dorozhko
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.