![]()  | 
	
 
  | 
		
			
  | 	
	
	
		
		|||||||
| Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны | 
![]()  | 
	
	
| 
		 | 
	Опции темы | Поиск в этой теме | Опции просмотра | 
| 
	 | 
| 
		 
			 
			#1  
			
			
			
			
		 
		
		
	 | 
|||
		
		
  | 
|||
| 
	
	
		
			
			 Уважаемые форумчане, подскажите алгоритм решения вот такой задачки: 
		
	
		
		
			имеется 16-цветное bitmap-изображение с разноцветными пятнами, необходимо подсчитать площадь каждого пятна и их количество. Понятно, что площадь одного пятна можно вычислить попиксельно, с толку сбивает то, что пятен одного цвета может быть несколько и все они неправильной формы. Может кто встречал такой алгоритм? Чтоб было понятнее о чем речь, прикрепила картинку.  | 
| 
		 
			 
			#2  
			
			
			
			
		 
		
		
	 | 
||||
		
		
  | 
||||
| 
	
	
		
			
			 Может, каким-нибудь волновым алгоритмом - пускать волну для определенного цвета з затуханием при выходе на другой цвет. Тока создать двумерный булев массив с размерностью как битмап и записывать, проходила там волна или нет. Соответственно, подсчитывать количество пикселов, по которым прошла волна - это и будет площадь. ИМХО. 
		
	
		
		
			Вот типа того. Но желательно, чтобы пятна были одноцветными, без "оттенков", подсчет идет строго по цвету. Или зделать небольшой припуск... Последний раз редактировалось YVitaliy, 02.02.2012 в 22:16.  | 
| 
		 
			 
			#3  
			
			
			
			
		 
		
		
	 | 
||||
		
		
  | 
||||
| 
	
	
		
			
			 Я бы создал на каждое пятно по региону (HRGN). А потом считал бы площадь региона. Функции накиданы на скорую руку, но рабочие: 
		
	
		
		
		
		
			
		
		
		
		
	
		
		
	
	
	1. Указываем битмап, точку, пустой регион и цвет - получите вместо пустого региона - регион пятна с указанным цветом. Код: 
	procedure _Do(bmp: TBitMap; X, Y: Integer; c: TColor; var r: hRgn);
  var
    rg_T: HRgn;
  begin
    if (bmp.Canvas.Pixels[X, Y] <> c) or PtInRegion(r, X, Y) then Exit;
    rg_T := CreateRectRgn(X, Y, X + 1 , Y + 1);
    CombineRgn(r, r, rg_T, RGN_OR);
    DeleteObject(rg_T);
    if X > 0 then _DO(bmp, X - 1, Y, c, r);
    if X < bmp.Width - 1 then _DO(bmp, X + 1, Y, c, r);
    if Y > 0 then _DO(bmp, X, Y - 1, c, r);
    if Y < bmp.Height - 1 then _DO(bmp, X, Y + 1, c, r);
  end;Код: 
	function RgnSquare(r: hRgn): Int64;
  type
   TRectArray = Array[0..9999] of TRect;
   PRectArray = ^TRectArray;
  var
    i: Integer;
    RgnData: PRgnData;
    RgnDataSize: DWord;
    RectArrayPtr: PRectArray;
  begin
    Result := 0;
    RgnDataSize:= GetRegionData(r, 0, nil);
    GetMem(RgnData, RgnDataSize);
    GetRegionData(r, RgnDataSize, RgnData);
    if RgnData^.rdh.nCount > 0 then
    begin
      RectArrayPtr:= @RgnData.Buffer;
      for i := 0 to RgnData^.rdh.nCount - 1 do
      with RectArrayPtr[i] do
      Result := Result + (Bottom - Top) * (Right - Left);
    end;
    FreeMem(RgnData);
  end;Код: 
	var c: TColor; rg_R: HRgn; begin c := Image1.Canvas.Pixels[0, 0]; rg_R := CreateRectRgn(0, 0, 0, 0); //================ _Do(Image1.Picture.Bitmap, 0, 0, c, rg_R); FillRgn(Canvas.Handle, rg_R, Canvas.Pen.Handle); ShowMessage(IntToStr(RgnSquare(rg_R))); //================ DeleteObject(rg_R); end;  | 
| 
		 
			 
			#4  
			
			
			
			
		 
		
		
	 | 
|||
		
		
  | 
|||
| 
	
	
		
			
			 Большое спасибо за ответы. Оба алгоритма прекрасно работают, если пятно заданного цвета одно. Проблемы начинаются, когда пятен одного цвета несколько - все суммируется в общую площадь. Как же быть? 
		
	
		
		
		
		
		
		
			P.S. Извините, YVitaliy, не заметила добавления, сейчас попробуем... Последний раз редактировалось entropy55, 03.02.2012 в 16:17.  | 
| 
		 
			 
			#5  
			
			
			
			
		 
		
		
	 | 
||||
		
		
  | 
||||
| 
	
	
		
			
			 Там у меня можно клик по имаге делать, соответственно справа показывает площадь и цвет пятна под курсором. И ничего не суммируется. В мемо просто выводится для примера площадь всех пятен по отдельности и суммарная. 
		
	
		
		
		
		
		
		
			И еще: поскольку подсчет - рекурсия, то вполне возможно переполнение стека при слишком болиших изображениях. Не проверял. Последний раз редактировалось YVitaliy, 03.02.2012 в 16:19.  | 
| 
		 
			 
			#6  
			
			
			
			
		 
		
		
	 | 
||||
		
		
  | 
||||
| 
	
	
		
			
			 Я бы работал по регионам. 
		
	
		
		
		
		
			
		
		
		
		
		
			1. Создем глобальный регион размером с картинку CreateRectRgn(0, 0, BitMap.Width, BitMap.Height) 2. Бегаем по строкам и столбцам битмапа 2.1 Если точка НЕ входит в глобальный регион, то идем в 2, иначе (2.2) 2.2 "выделяем пятно" от этой точки процедурой _Do из моего предыдущего поста. 2.3 Выделив регион удаляем, его из глобального По такому алгоритму пятна никак не сольются воедино. Последний раз редактировалось dr. F.I.N., 03.02.2012 в 16:20.  | 
| 
		 
			 
			#7  
			
			
			
			
		 
		
		
	 | 
|||
		
		
  | 
|||
| 
	
	
		
			
			 Ура! Дошло! dr. F.I.N. и YVitaliy, спасибо вам большое! 
		
	
		
		
		
		
		
	
		
		
	
	
	 |