Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Image 视觉从图像中选择图像部分?_Image_Delphi_Delphi Xe6 - Fatal编程技术网

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位置向右至子图像右边界