Image 视觉从图像中选择图像部分?
问候 我有特别的形象:Image 视觉从图像中选择图像部分?,image,delphi,delphi-xe6,Image,Delphi,Delphi Xe6,问候 我有特别的形象: 使用哪种alghoritm可以从该图像中选择图像部分&直观地查看当前选择的内容? 每个图像部分用特殊颜色(示例中为紫红色)以1像素分隔 添加: 子图像(或其中任何一个)可以有任何形式。在我看来,你有一个矩形的紫红色海洋,其中包含许多非紫红色岛屿。你想识别那些岛屿。一个简单的算法如下所示: 从图像的一角开始,比如说左上角 逐像素、逐行浏览图像。因此,从左到右处理第一行,然后处理下一行,依此类推 当你找到一个非紫红色的像素,这是一个岛屿的左上角。现在找到岛上的其他地方。沿着
使用哪种alghoritm可以从该图像中选择图像部分&直观地查看当前选择的内容? 每个图像部分用特殊颜色(示例中为紫红色)以1像素分隔 添加:
子图像(或其中任何一个)可以有任何形式。在我看来,你有一个矩形的紫红色海洋,其中包含许多非紫红色岛屿。你想识别那些岛屿。一个简单的算法如下所示:
下面是一个在图像中查找子图像的示例 此示例能够找到任何具有凸形状(矩形、三角形、圆等)的子图像。但它不能正确地处理凹面形状。对于那个些你们需要修改算法的人,一旦你们找到了第一个像素,你们就可以用和flod fill相似的算法去扫描所有的邻近像素 代码如下:
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.
单元2;
接口
使用
Winapi.Windows、Winapi.Messages、System.SysUtils、System.Variants、System.Classes、Vcl.Graphics、,
Vcl.控件、Vcl.窗体、Vcl.对话框、Vcl.StdCtrls、Vcl.ExtCtrls、Vcl.ComCtrls;
类型
TSubImage=记录
左边界:整数;
右边界:整数;
上界:整数;
下限:整数;
结束;
ASubImages=Tsubimages的数组;
TForm2=类别(TForm)
按钮1:t按钮;
图片来源:TImage;
ListView1:TListView;
选择图像:TImage;
程序按钮1点击(发送方:ToObject);
过程列表视图1所选项目(发件人:ToObject;项目:TListItem;
选择:布尔值);
过程表单创建(发送方:ToObject);
过程选择ImageMouseMove(发送方:ToObject;Shift:TShiftState;X,
Y:整数);
私有的
{私有声明}
公众的
{公开声明}
结束;
变量
表2:TForm2;
子图像:ASubImages;
实施
{$R*.dfm}
过程查找子图像(位图:TBitmap;var子图像:ASubImages);
变量X,Y,I:整数;
//我们用来存储哪个像素属于哪个图像的2D数组
SubImagesMap:整数数组的数组;
开始
//将地图尺寸设置为我们扫描的TBitmap的相同尺寸
设置长度(子图像映射、位图宽度+1、位图高度+1);
对于Y:=0到位图.Height-1 do
开始
对于X:=0到位图宽度-1 do
开始
//检查当前像素颜色是否不是背景色。
如果Bitmap.Canvas.Pixels[X,Y]clFuchsia那么
开始
//检查是否已向右移动(当前像素X位置>0)
如果X>0,则
开始
//检查左侧的像素是否已分配给子图像编号
//并将当前像素分配给相同的子图像编号,因为它们是邻接的
如果子映像映射[X-1,Y]0,则
开始
子图像映射[X,Y]:=子图像映射[X-1,Y];
//这里我们检查当前像素是否位于子图像之外
//并相应地进行调整
//检查是否像素X位置向左到子图像左边界
如果子映像[SubImagesMap[X,Y]-1]。LeftBound>X,则
//将子图像向左移动以匹配像素X位置
子映像[SubImagesMap[X,Y]-1]。左边界:=X;
//检查是否像素X位置向右至子图像右边界
如果子映像[SubImagesMap[X,Y]-1],则右边界Y,则
//将子图像上界移动到匹配像素Y位置
子映像[SubImagesMap[X,Y]-1]。上界:=Y;
//检查是否像素Y位置向下至子图像底部边界
如果子映像[SubImagesMap[X,Y]-1],则底部绑定0)
如果Y>0,则
开始
//检查上面的像素是否已分配给子图像编号
//并将当前像素分配给相同的子图像编号,因为它们是邻接的
如果子映像映射[X,Y-1]0,则
开始
子图像映射[X,Y]:=子图像映射[X,Y-1];
//这里我们检查当前像素是否位于子图像之外
//并相应地进行调整
//检查是否像素X位置向左到子图像左边界
如果子映像[SubImagesMap[X,Y]-1]。LeftBound>X,则
//将子图像向左移动以匹配像素X位置
子映像[SubImagesMap[X,Y]-1]。左边界:=X;
//检查是否像素X位置向右至子图像右边界