問候!從圖像中選擇圖像部分?
我有特殊的圖像:
憑藉其alghoritm我可以從這個圖像&選擇圖像部分在視覺上看出了我的currentry選擇?每個圖像部分由其他人用1個像素用特殊顏色(例如Fuchsia)分隔。
加入:
子圖象(或其中的任何)可以具有任何形式。
問候!從圖像中選擇圖像部分?
我有特殊的圖像:
憑藉其alghoritm我可以從這個圖像&選擇圖像部分在視覺上看出了我的currentry選擇?每個圖像部分由其他人用1個像素用特殊顏色(例如Fuchsia)分隔。
加入:
子圖象(或其中的任何)可以具有任何形式。
以下是查找圖像中子圖像的示例。
這個例子能夠找到凸形(矩形,三角形,圓形等)的任何子圖像。但它在凹形上不能正確工作。對於那些你需要修改算法,以便一旦你找到第一個像素,然後去掃描與flod填充類似算法的所有鄰居。
這裏是代碼:
unit Unit2;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls, Vcl.ComCtrls;
type
TSubImage = record
LeftBound: Integer;
RightBound: Integer;
TopBound: Integer;
BottomBound: Integer;
end;
ASubImages = Array of TSubImage;
TForm2 = class(TForm)
Button1: TButton;
SourceImage: TImage;
ListView1: TListView;
SelectionImage: TImage;
procedure Button1Click(Sender: TObject);
procedure ListView1SelectItem(Sender: TObject; Item: TListItem;
Selected: Boolean);
procedure FormCreate(Sender: TObject);
procedure SelectionImageMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form2: TForm2;
SubImages: ASubImages;
implementation
{$R *.dfm}
procedure FindSubimages(Bitmap: TBitmap; var Subimages: ASubImages);
var X,Y,I: Integer;
//2D array we use to store to which image does which pixel belong
SubImagesMap: Array of Array of Integer;
begin
//Set the map dimension to the same dimension of TBitmap we scan
SetLength(SubImagesMap,Bitmap.Width+1,Bitmap.Height+1);
for Y := 0 to Bitmap.Height-1 do
begin
for X := 0 to Bitmap.Width-1 do
begin
//Check to see if current pixel color is not of background color.
if Bitmap.Canvas.Pixels[X,Y] <> clFuchsia then
begin
//Check if we already moved rightward (current pixel X postion > 0)
if X > 0 then
begin
//Check if pixel to the left has already been assigned to a subimage number
//and assign current pixel to the same subimage number since they are adjenct
if SubImagesMap[X-1,Y] <> 0 then
begin
SubImagesMap[X,Y] := SubImagesMap[X-1,Y];
//Here we are checking to see if current pixel is placed outside of subimage
//bonds and adjust them acordingly
//Check to se if pixel X position is leftwards to subimages left bound
if Subimages[SubImagesMap[X,Y]-1].LeftBound > X then
//Move subimage left bound to match pixel X position
Subimages[SubImagesMap[X,Y]-1].LeftBound := X;
//Check to se if pixel X position is rightwards to subimages right bound
if Subimages[SubImagesMap[X,Y]-1].RightBound < X then
//Move subimage right bound to match pixel X position
Subimages[SubImagesMap[X,Y]-1].RightBound := X;
//Check to se if pixel Y position is upwards to subimages top bound
if Subimages[SubImagesMap[X,Y]-1].TopBound > Y then
//Move subimage top bound to match pixel Y position
Subimages[SubImagesMap[X,Y]-1].TopBound := Y;
//Check to se if pixel Y position is downwards to subimages bottom bound
if Subimages[SubImagesMap[X,Y]-1].BottomBound < Y then
//Move subimage bottom bound to match pixel Y position
Subimages[SubImagesMap[X,Y]-1].BottomBound := Y;
end;
end;
//Check if we already moved downward (current pixel Y position > 0)
if Y > 0 then
begin
//Check if pixel above has already been assigned to a subimage number
//and assign current pixel to the same subimage number since they are adjenct
if SubImagesMap[X,Y-1] <> 0 then
begin
SubImagesMap[X,Y] := SubImagesMap[X,Y-1];
//Here we are checking to see if current pixel is placed outside of subimage
//bonds and adjust them acordingly
//Check to se if pixel X position is leftwards to subimages left bound
if Subimages[SubImagesMap[X,Y]-1].LeftBound > X then
//Move subimage left bound to match pixel X position
Subimages[SubImagesMap[X,Y]-1].LeftBound := X;
//Check to se if pixel X position is rightwards to subimages right bound
if Subimages[SubImagesMap[X,Y]-1].RightBound < X then
//Move subimage right bound to match pixel X position
Subimages[SubImagesMap[X,Y]-1].RightBound := X;
//Check to se if pixel Y position is upwards to subimages top bound
if Subimages[SubImagesMap[X,Y]-1].TopBound > Y then
//Move subimage top bound to match pixel Y position
Subimages[SubImagesMap[X,Y]-1].TopBound := Y;
//Check to se if pixel Y position is downwards to subimages bottom bound
if Subimages[SubImagesMap[X,Y]-1].BottomBound < Y then
//Move subimage bottom bound to match pixel Y position
Subimages[SubImagesMap[X,Y]-1].BottomBound := Y;
end;
end;
//Check to see if current pixel has already been asigned a sibimage number
//I not we create a new subimage entry and assign its number to current pixel
if SubImagesMap[X,Y] = 0 then
begin
//Increase the size of dynamic array storing subimage records
SetLength(SubImages,Length(SubImages)+1);
//Assing current pixel the number of newly created subimage
SubImagesMap[X,Y] := Length(SubImages);
//Set subimage initial bounds which are coordinates of one pixel
//since we created new subimage for this pixel
SubImages[SubImagesMap[X,Y]-1].LeftBound := X;
SubImages[SubImagesMap[X,Y]-1].RightBound := X;
SubImages[SubImagesMap[X,Y]-1].TopBound := Y;
SubImages[SubImagesMap[X,Y]-1].BottomBound := Y;
end;
end;
end;
end;
//Reduce the size of SubImageMap array to free its memory
//Since SubImageMap is local array this is optional
SetLength(SubImagesMap,0,0);
end;
procedure TForm2.Button1Click(Sender: TObject);
var I: Integer;
ListItem: TListItem;
ListColumn: TListColumn;
begin
//Our procedure for finding subimages. It accepts two parameters
//First parameter is reference to TBitmap object containing original image
//Second is reference to variable in which subimage bouns will be stored to
FindSubimages(SourceImage.Picture.Bitmap, Subimages);
//Lets show our results in more readable format
//First we change the ListView style to vsReport so we can show our results
//in multiple columns
ListView1.ViewStyle := vsReport;
//Then we add necessary columns
ListColumn := ListView1.Columns.Add;
ListColumn.Caption := 'Subimage number';
ListColumn.Width := 100;
ListColumn := ListView1.Columns.Add;
ListColumn.Caption := 'Left Bound';
ListColumn.Width := 80;
ListColumn := ListView1.Columns.Add;
ListColumn.Caption := 'Right Bound';
ListColumn.Width := 80;
ListColumn := ListView1.Columns.Add;
ListColumn.Caption := 'Top Bound';
ListColumn.Width := 80;
ListColumn := ListView1.Columns.Add;
ListColumn.Caption := 'Bottom Bound';
ListColumn.Width := 80;
//Iterate through all subimages and add data to ListView
for I := 0 to Length(Subimages)-1 do
begin
//Ad new item to list view
ListItem := ListView1.Items.Add;
//Use the reference of newly added item to set caption which will be the text
//in first column
ListItem.Caption := IntToStr(I+1);
//Add aditional subitems. Each of this subitems is shown in its own column
//NOTE: Make sure to have enough columns to show all subitems
//If you wanna field in certain column to be empty just pass an empty string ''
ListItem.SubItems.Add(IntToStr(SubImages[I].LeftBound));
ListItem.SubItems.Add(IntToStr(SubImages[I].RightBound));
ListItem.SubItems.Add(IntToStr(SubImages[I].TopBound));
ListItem.SubItems.Add(IntToStr(SubImages[I].BottomBound));
end;
end;
procedure TForm2.FormCreate(Sender: TObject);
begin
//Make selection image 2 pixels larger so we will never draw right to the edge
//and therefore can easily use its defult transparency
SelectionImage.Width := SourceImage.Width+2;
SelectionImage.Height := SourceImage.Height+2;
//Shift selector image position one to the left and one up to be centered above
//SourceIMage.
SelectionImage.Left := SourceImage.Left-1;
SelectionImage.Top := SourceImage.Top-1;
end;
procedure TForm2.ListView1SelectItem(Sender: TObject; Item: TListItem;
Selected: Boolean);
var Rect: TRect;
begin
//Use SubImage bounds to form rectagnle we will use for our selection
Rect.Left := SubImages[Item.Index].LeftBound+1;
Rect.Right := SubImages[Item.Index].RightBound+2;
Rect.Top := SubImages[Item.Index].TopBound+1;
Rect.Bottom := SubImages[Item.Index].BottomBound+2;
//Clear previous selection
SelectionImage.Canvas.Brush.Color := clFuchsia;
SelectionImage.Canvas.FillRect(SelectionImage.Canvas.ClipRect);
//Draw new selection rectangle
SelectionImage.Canvas.Brush.Color := clLime;
SelectionImage.Canvas.FrameRect(Rect);
end;
procedure TForm2.SelectionImageMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
begin
Form2.Caption := IntToStr(X);
end;
end.
正如我所看到的,你有一個矩形的紫紅色的海洋,其中包含一些非紫紅色的島嶼。你想識別這些島嶼。一個簡單的算法如下:
任何島嶼都可能有任何形式。好主意,我會嘗試使用嚴厲 – AlexLL 2014-08-31 14:14:15
這個問題表明矩形島。無論如何,延伸到任意形狀的島嶼並不難。 – 2014-08-31 16:01:01
據我所知,沒有存儲或讀取圖像的子圖像的標準,但這是大多數皮膚庫做的任務之一。所以你可以閱讀它們的源代碼(比如Vcl樣式)並檢查它是如何工作的。基本思想是存儲每個圖像的邊界,然後將該圖像與對象進行對應 – RRUZ 2014-08-30 22:54:14
-1 *子圖像(或它們中的任何一個)可以具有任何形式。*在有答案後添加嚴格的限制並不是很酷 – 2014-09-01 20:01:47