一种简单的图像分析

简介

一种简单的边界分析,通过相邻的像素的灰度进行判断,计算出边界。

测试1

原图

结果

测试2

原图

结果

代码说明

主要的技术在makeTable过程中,这个过程主要执行了以下几步

  1. 计算每个像素的灰度
  2. 计算相邻多个像素的最大灰度差
  3. 统计灰度差,计算出阈值
  4. 根据阈值,计算出边界,并标注在图像上

procedure makeTable(img: TBitmap32);
var
  w, h, w_r, h_r, x, y, k, r_count, Pcount: Integer;
  bmp2, bmp: TBitmap32;
  blist: TByteTable;
  blist_diff: TByteTable;
  b, b1, b2, maxa: byte;
  c32: TColor32Entry;
  sum, stepCount, count: integer;
  idx, i, j, s_x_1, s_x_2: integer;
  s_y_1, s_y_2: integer;
  c_b: array[0..255] of integer;
  FilterB: Byte;
  Filter_Count: integer;
  Filter_Sum: integer;

  RectList: array of array of TRectRec;
  r: Trect;
  pt_1, path: array of TPoint;
  fillcount, maxfillcount: integer;
  function check_r(i, j: integer; pt: array of TPoint): Boolean;
  var
    idx: integer;
  begin
    Result := false;
    if RectList[i, j].count <= 0 then
      exit;

    for idx := 0 to high(pt) do
      begin
        if RectList[i + pt[idx].X, j + pt[idx].y].count > 0 then
          begin
            Result := false;
            Exit;
          end;
      end;
    Result := true;
  end;
  procedure getFill(x, y: integer; pt: array of TPoint; MaxCount: integer; var path: array of TPoint; var count: integer);
  var
    idx: integer;
    ax, ay: integer;
  begin
    if x < 0 then
      Exit;
    if y < 0 then
      Exit;
    if x >= w_r then
      Exit;
    if y >= h_r then
      Exit;
    if RectList[x, y].count <= 0 then
      Exit;
    if count >= MaxCount then
      exit;
    for idx := count - 1 downto 0 do
      begin
        if (path[idx].X = x) and (path[idx].y = y) then
          begin
            Exit;
          end;
      end;
    path[count] := Point(x, y);
    inc(count);
    if count >= MaxCount then
      exit;
    for idx := 0 to high(pt) do
      begin
        ax := x + pt[idx].X;
        ay := y + pt[idx].Y;
        getFill(ax, ay, pt, MaxCount, path, count);
      end;
  end;
begin
  w := img.Width;
  h := img.Height;

  SetLength(blist, w);
  for x := 0 to w - 1 do
    SetLength(blist[x], h);
  SetLength(blist_diff, w);
  for x := 0 to w - 1 do
    SetLength(blist_diff[x], h);

  for x := 0 to w - 1 do
    for y := 0 to h - 1 do
      begin
        c32.ARGB := img.Pixel[x, y];
        b := (77 * c32.R + 150 * c32.G + 29 * c32.B) shr 8;
        blist[x, y] := b;
      end;

  bmp2 := TBitmap32.Create;
  bmp2.SetSize(w, h);
  maxa := 0;
  stepCount := 5;
  for x := 0 to w - 1 do
    for y := 0 to h - 1 do
      begin
        count := min(x - 0 + 1, stepCount);
        s_x_1 := getsum(blist, x, y, -1, 0, count);
        count := min(w - x, stepCount);
        s_x_2 := getsum(blist, x, y, 1, 0, count);

        count := min(y - 0 + 1, stepCount);
        s_y_1 := getsum(blist, x, y, 0, -1, count);
        count := min(h - y, stepCount);
        s_y_2 := getsum(blist, x, y, 0, 1, count);

        b := max(abs(s_x_1 - s_x_2), abs(s_y_1 - s_y_2));
        blist_diff[x, y] := b;
        if b > maxa then
          maxa := b;
      end;

  ZeroMemory(@(c_b[0]), length(c_b) * sizeof(i));
  Pcount := 0;
  for x := 0 to w - 1 do
    for y := 0 to h - 1 do
      begin
        b := blist_diff[x, y];
        b := 255 * b div maxa;
        blist_diff[x, y] := b;
        inc(c_b[b]);
        inc(Pcount);
      end;
  FilterB := 0;
  count := 0;
  for i := 0 to 255 do
    begin
      inc(count, c_b[i]);
      if count > (Pcount div 2) then
        begin
          FilterB := i ;
          Break;
        end
    end;

  Pcount := 0;
  for x := 0 to w - 1 do
    for y := 0 to h - 1 do
      begin

        if blist_diff[x, y] < FilterB then
          blist_diff[x, y] := 0;
      end;
  x := 0;
  y := 0;
  r_count := 10;
  w_r := (w - 1) div r_count + 1;
  h_r := (h - 1) div r_count + 1;

  SetLength(RectList, w_r);
  for x := 0 to w_r - 1 do
    SetLength(RectList[x], h_r);

  for i := 0 to w_r - 1 do
    for j := 0 to h_r - 1 do
      begin
        x := (i) * r_count;
        y := (j) * r_count;
        r.Left := x;
        r.Top := y;
        r.Right := Min(x + r_count, w);
        r.Bottom := Min(y + r_count, h);
        RectList[i, j].rect := r;
        RectList[i, j].sum := 0;
        RectList[i, j].count := 0;
      end;
  count := 0;
  sum := 0;
  for x := 0 to w - 1 do
    for y := 0 to h - 1 do
      begin
        b := blist_diff[x, y];
        if b = 0 then
          Continue;
        i := x div (r_count);
        j := y div (r_count);
        inc(RectList[i, j].sum, b);
        inc(RectList[i, j].count);
        inc(sum, b);
        inc(count);
      end;

  Filter_Sum := sum div count;
  Filter_Count := max(r_count, count div (w_r * h_r));
  setlength(pt_1, 8);
  pt_1[0] := Point(-1, -1);
  pt_1[1] := Point(0, -1);
  pt_1[2] := Point(+1, -1);
  pt_1[3] := Point(-1, 0);
  pt_1[4] := Point(+1, 0);
  pt_1[5] := Point(-1, +1);
  pt_1[6] := Point(0, +1);
  pt_1[7] := Point(-1, +1);

  for i := 0 to w_r - 1 do
    for j := 0 to h_r - 1 do
      begin
        if RectList[i, j].count < Filter_Count then
          begin
            RectList[i, j].count := 0
          end
        else
          begin
            if RectList[i, j].sum < (Filter_Sum * RectList[i, j].count) then
              begin
                RectList[i, j].count := 0;
              end;


          end;
      end;
  setlength(path, 255);
  maxfillcount := 50;

  for i := 0 to w_r - 1 do
    for j := 0 to h_r - 1 do
      begin
        fillcount := 0;
        getFill(i, j, pt_1, maxfillcount + 1, path, fillcount);
        if fillcount <= maxfillcount then
          begin
            for idx := 0 to fillcount - 1 do
              begin
                RectList[path[idx].X, path[idx].y].count := 0;
              end;
          end;
      end;
  setlength(pt_1, 0);
  setlength(path, 0);


  Pcount := 0;
  for x := 1 to w - 2 do
    for y := 1 to h - 2 do
      begin
        if blist_diff[x, y] > 0 then
          inc(Pcount);
      end;
  c32.ARGB := clRed32;
  for x := 0 to w - 1 do
    for y := 0 to h - 1 do
      begin
        i := x div (r_count);
        j := y div (r_count);
        if RectList[i, j].count > 0 then
          c32.A := blist_diff[x, y]
        else
          c32.A := 0;
        bmp2.Pixel[x, y] := c32.ARGB;
      end;
  bmp2.DrawMode := dmBlend;
  for i := 0 to w_r - 1 do
    for j := 0 to h_r - 1 do
      begin
        if RectList[i, j].count > 0 then
          img.FrameRectS(RectList[i, j].rect, clBlue32);
      end;
  img.Draw(0, 0, bmp2);
  FreeAndNil(bmp2);

  for x := 0 to w - 1 do
    SetLength(blist[x], 0);
  SetLength(blist, 0);
  for x := 0 to w - 1 do
    SetLength(blist_diff[x], 0);
  SetLength(blist_diff, 0);
  for x := 0 to w_r - 1 do
    SetLength(RectList[x], 0);
  setlength(RectList, 0);
end;

完整代码 

unit Unit1;interfaceusesWindows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,Dialogs, jpeg, gr32, ExtCtrls, StdCtrls;typeTForm1 = class(TForm)ScrollBox1: TScrollBox;Panel1: TPanel;Image1: TImage;ComboBox1: TComboBox;procedure FormCreate(Sender: TObject);private{ Private declarations }public{ Public declarations }end;varForm1: TForm1;implementation{$R *.dfm}
uses math;
typeTByteTable = array of array of Byte;TRectRec = recordrect: TRect;b: Byte;sum: integer;count: integer;end;function getsum(table: TByteTable; ax, ay, ix, iy, count: integer): integer;
vari, x, y: integer;
beginResult := 0;x := ax;y := ay;for i := 1 to count dobegininc(Result, table[x, y]);inc(x, ix);inc(y, iy);end;Result := Result div count;
end;procedure makeTable(img: TBitmap32);
varw, h, w_r, h_r, x, y, k, r_count, Pcount: Integer;bmp2, bmp: TBitmap32;blist: TByteTable;blist_diff: TByteTable;b, b1, b2, maxa: byte;c32: TColor32Entry;sum, stepCount, count: integer;idx, i, j, s_x_1, s_x_2: integer;s_y_1, s_y_2: integer;c_b: array[0..255] of integer;FilterB: Byte;Filter_Count: integer;Filter_Sum: integer;RectList: array of array of TRectRec;r: Trect;pt_1, path: array of TPoint;fillcount, maxfillcount: integer;function check_r(i, j: integer; pt: array of TPoint): Boolean;varidx: integer;beginResult := false;if RectList[i, j].count <= 0 thenexit;for idx := 0 to high(pt) dobeginif RectList[i + pt[idx].X, j + pt[idx].y].count > 0 thenbeginResult := false;Exit;end;end;Result := true;end;procedure getFill(x, y: integer; pt: array of TPoint; MaxCount: integer; var path: array of TPoint; var count: integer);varidx: integer;ax, ay: integer;beginif x < 0 thenExit;if y < 0 thenExit;if x >= w_r thenExit;if y >= h_r thenExit;if RectList[x, y].count <= 0 thenExit;if count >= MaxCount thenexit;for idx := count - 1 downto 0 dobeginif (path[idx].X = x) and (path[idx].y = y) thenbeginExit;end;end;path[count] := Point(x, y);inc(count);if count >= MaxCount thenexit;for idx := 0 to high(pt) dobeginax := x + pt[idx].X;ay := y + pt[idx].Y;getFill(ax, ay, pt, MaxCount, path, count);end;end;
beginw := img.Width;h := img.Height;SetLength(blist, w);for x := 0 to w - 1 doSetLength(blist[x], h);SetLength(blist_diff, w);for x := 0 to w - 1 doSetLength(blist_diff[x], h);for x := 0 to w - 1 dofor y := 0 to h - 1 dobeginc32.ARGB := img.Pixel[x, y];b := (77 * c32.R + 150 * c32.G + 29 * c32.B) shr 8;blist[x, y] := b;end;bmp2 := TBitmap32.Create;bmp2.SetSize(w, h);maxa := 0;stepCount := 5;for x := 0 to w - 1 dofor y := 0 to h - 1 dobegincount := min(x - 0 + 1, stepCount);s_x_1 := getsum(blist, x, y, -1, 0, count);count := min(w - x, stepCount);s_x_2 := getsum(blist, x, y, 1, 0, count);count := min(y - 0 + 1, stepCount);s_y_1 := getsum(blist, x, y, 0, -1, count);count := min(h - y, stepCount);s_y_2 := getsum(blist, x, y, 0, 1, count);b := max(abs(s_x_1 - s_x_2), abs(s_y_1 - s_y_2));blist_diff[x, y] := b;if b > maxa thenmaxa := b;end;ZeroMemory(@(c_b[0]), length(c_b) * sizeof(i));Pcount := 0;for x := 0 to w - 1 dofor y := 0 to h - 1 dobeginb := blist_diff[x, y];b := 255 * b div maxa;blist_diff[x, y] := b;inc(c_b[b]);inc(Pcount);end;FilterB := 0;count := 0;for i := 0 to 255 dobegininc(count, c_b[i]);if count > (Pcount div 2) thenbeginFilterB := i ;Break;endend;Pcount := 0;for x := 0 to w - 1 dofor y := 0 to h - 1 dobeginif blist_diff[x, y] < FilterB thenblist_diff[x, y] := 0;end;x := 0;y := 0;r_count := 10;w_r := (w - 1) div r_count + 1;h_r := (h - 1) div r_count + 1;SetLength(RectList, w_r);for x := 0 to w_r - 1 doSetLength(RectList[x], h_r);for i := 0 to w_r - 1 dofor j := 0 to h_r - 1 dobeginx := (i) * r_count;y := (j) * r_count;r.Left := x;r.Top := y;r.Right := Min(x + r_count, w);r.Bottom := Min(y + r_count, h);RectList[i, j].rect := r;RectList[i, j].sum := 0;RectList[i, j].count := 0;end;count := 0;sum := 0;for x := 0 to w - 1 dofor y := 0 to h - 1 dobeginb := blist_diff[x, y];if b = 0 thenContinue;i := x div (r_count);j := y div (r_count);inc(RectList[i, j].sum, b);inc(RectList[i, j].count);inc(sum, b);inc(count);end;Filter_Sum := sum div count;Filter_Count := max(r_count, count div (w_r * h_r));setlength(pt_1, 8);pt_1[0] := Point(-1, -1);pt_1[1] := Point(0, -1);pt_1[2] := Point(+1, -1);pt_1[3] := Point(-1, 0);pt_1[4] := Point(+1, 0);pt_1[5] := Point(-1, +1);pt_1[6] := Point(0, +1);pt_1[7] := Point(-1, +1);for i := 0 to w_r - 1 dofor j := 0 to h_r - 1 dobeginif RectList[i, j].count < Filter_Count thenbeginRectList[i, j].count := 0endelsebeginif RectList[i, j].sum < (Filter_Sum * RectList[i, j].count) thenbeginRectList[i, j].count := 0;end;end;end;setlength(path, 255);maxfillcount := 50;for i := 0 to w_r - 1 dofor j := 0 to h_r - 1 dobeginfillcount := 0;getFill(i, j, pt_1, maxfillcount + 1, path, fillcount);if fillcount <= maxfillcount thenbeginfor idx := 0 to fillcount - 1 dobeginRectList[path[idx].X, path[idx].y].count := 0;end;end;end;setlength(pt_1, 0);setlength(path, 0);Pcount := 0;for x := 1 to w - 2 dofor y := 1 to h - 2 dobeginif blist_diff[x, y] > 0 theninc(Pcount);end;c32.ARGB := clRed32;for x := 0 to w - 1 dofor y := 0 to h - 1 dobegini := x div (r_count);j := y div (r_count);if RectList[i, j].count > 0 thenc32.A := blist_diff[x, y]elsec32.A := 0;bmp2.Pixel[x, y] := c32.ARGB;end;bmp2.DrawMode := dmBlend;for i := 0 to w_r - 1 dofor j := 0 to h_r - 1 dobeginif RectList[i, j].count > 0 thenimg.FrameRectS(RectList[i, j].rect, clBlue32);end;img.Draw(0, 0, bmp2);FreeAndNil(bmp2);for x := 0 to w - 1 doSetLength(blist[x], 0);SetLength(blist, 0);for x := 0 to w - 1 doSetLength(blist_diff[x], 0);SetLength(blist_diff, 0);for x := 0 to w_r - 1 doSetLength(RectList[x], 0);setlength(RectList, 0);
end;procedure TForm1.FormCreate(Sender: TObject);
varfn: string;bmp: TBitmap32;
beginfn := ExtractFilePath(Application.ExeName) + 'IMG_0023.JPG';bmp := TBitmap32.Create;bmp.LoadFromFile(fn);fn := fn + '.bmp';makeTable(bmp);bmp.SaveToFile(fn);Image1.Picture.LoadFromFile(fn);
end;end.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/857528.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

每日一题——冒泡排序

C语言——冒泡排序 冒泡排序练习 前言&#xff1a;CSDN的小伙伴们&#xff0c;大家好&#xff01;今天我来给大家分享一种解题思想——冒泡排序。 冒泡排序 冒泡法的核心思想&#xff1a;两两相邻的元素进行比较 2.冒泡排序的算法描述如下。 (1)比较相邻的元素。如果第一 个比…

如何用Go语言实现一个基于宏系统的解释器?

步骤1&#xff1a;定义语言的语法规则 首先&#xff0c;你需要定义你的宏系统语言的基本语法规则。这通常包括关键字、标识符、操作符、表达式等元素的定义。 步骤2&#xff1a;词法分析&#xff08;Lexical Analysis&#xff09; 词法分析是将源代码分解成一个个的词素&…

第6集《大乘起信论》

请大家打开《讲义》第十一页。 我们上一堂课程讲到马鸣菩萨造作本论的因缘&#xff0c;简单的说明马鸣菩萨之所以造作本论&#xff0c;是要成就大乘的信、解、行、证四种功德。这个信、解、行是大乘的因相&#xff0c;证是大乘的果相&#xff0c;所以说有如是等因缘&#xff0…

揭秘软件功能测试:如何精准锁定测试需求?

软件功能测试在确定测试需求时&#xff0c;可以遵循以下步骤和依据&#xff1a; 一、确定测试需求的步骤 了解测试背景和目的&#xff1a; 了解软件系统的应用领域、用户群体、使用场景等信息。明确测试的目的和测试范围&#xff0c;以便有针对性地进行测试。分析软件系统&am…

展讯-源码编译

1.硬件要求 编译主机要求&#xff0c;注意尽量不要使用虚拟机 CPU&#xff1a;Intel(R) Core(TM) i7-4790 CPU 3.60 GHz 内存&#xff1a;8G 硬盘&#xff1a;500G SSD Ubuntu 版本&#xff1a;Ubuntu 64-bit 14.04.5 LTS 这是最低版本要求&#xff0c;实际性能越高越好 2…

从零到一学FFmpeg:av_interleaved_write_frame 函数详析与实战

文章目录 前言一、函数原型二、功能描述三、使用场景四、使用实例 前言 av_interleaved_write_frame是FFmpeg库中的一个函数&#xff0c;用于将一个已编码的媒体数据包&#xff08;AVPacket&#xff09;写入到输出媒体文件或流中。 此函数特别关注于维护正确的交错&#xff08…

【机器学习 复习】 第1章 概述

一、概念 1.机器学习是一种通过先验信息来提升模型能力的方式。 即从数据中产生“模型”( model )的算法&#xff0c;然后对新的数据集进行预测。 2.数据集&#xff08;Dataset&#xff09;&#xff1a;所有数据的集合称为数据集。 训练集&#xff1a;用来训练出一个适合模…

【JavaScript脚本宇宙】终极对决:六大虚拟DOM库横评

深度剖析&#xff1a;六大虚拟DOM库的奥秘与应用场景 前言 虚拟DOM&#xff08;Document Object Model&#xff09;是用于表示和操作HTML文档的抽象数据结构。虚拟DOM库是构建用户界面的重要工具&#xff0c;它们提供了高效的更新机制、组件化开发等功能&#xff0c;使开发者…

wpfui:一个开源免费具有现代化设计趋势的WPF控件库

wpfui介绍 wpfui是一款开源免费&#xff08;MIT协议&#xff09;具有现代化设计趋势的WPF界面库。wpfui为wpf的界面开发提供了流畅的体验&#xff0c;提供了一个简单的方法&#xff0c;让使用WPF编写的应用程序跟上现代设计趋势。截止写这篇文章&#xff0c;该项目获得了6.7k …

YYU-5/80-260mm型钢筋残余变形测试仪 电子引伸计

YYU-5/80-260mm型钢筋接头专用引伸计&#xff0c;是按照《JGJ 107 2010 钢筋技术连接技术规程》的技术要求设计的&#xff0c;专门用于测试钢筋接头残余变形的双向平均引伸计&#xff0c;其标距可以根据钢筋直径要求进行调整。 完全符合《JGJ 107 2010 钢筋技术连接技术规程》…

信创适配评测

概叙 信创科普参考&#xff1a;全面国产化之路-信创-CSDN博客 有必要再解释一下两个名词“28N”&#xff0c;“79号文件”&#xff0c;因为“28N”指定了由政府牵头从各领域开启国产化的基调&#xff0c;而“79号文件”则指定了国产化的截止日期2027年。 信创的本质是实现中国信…

EOS black灵魂回响黑色无法联机/联机报错/联机失败怎么办

灵魂回响黑色EOS black中的职业系统&#xff0c;自由度非常高。从人物属性的精细调整&#xff0c;到装备属性的独特搭配&#xff0c;再到技能的个性化组合&#xff0c;每一步都充满了无限可能。更为惊喜的是&#xff0c;游戏中的角色职业不是一成不变的&#xff0c;而是随着手中…

从0开发一个Chrome插件:调试与优化

前言 这是《从0开发一个Chrome插件》系列的第二十篇文章,本系列教你如何从0去开发一个Chrome插件,每篇文章都会好好打磨,写清楚我在开发过程遇到的问题,还有开发经验和技巧。 专栏: 从0开发一个Chrome插件:什么是Chrome插件?从0开发一个Chrome插件:开发Chrome插件的必…

webcomponents学习

一、新建index.html文件 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><title>Document</title>…

Springboot3.3 整合Cassandra 4.1.5

一、数据库搭建 -- 创建Keyspace CREATE KEYSPACE school WITH replication {class:SimpleStrategy, replication_factor : 1};-- 创建表 CREATE TABLE student(id int PRIMARY KEY, name text, age int, genders int, address text ,interest set<text>,phone lis…

【C++】关于代码编译自动更新版本的问题

在写代码的时候&#xff0c;总是需要添加一个版本号&#xff0c;用于后续的版本管理 我常遇到的一个问题是&#xff0c;开发过程中&#xff0c;不一定会记得这件事情&#xff0c;导致有时候会出现同样的版本 于是希望有一个方式&#xff0c;能在编译代码的时候自动生成一个版…

【Proteus仿真】【Arduino单片机】汽车倒车报警系统设计

文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用Proteus8仿真Arduinno单片机控制器&#xff0c;使用LCD1602液晶、按键、继电器电机模块、DS18B20温度传感器、蜂鸣器LED、HCSR04超声波等。 主要功能&#xff1a; 系统运行后&#xff0c;LCD16…

Maven Wrapper安装指令

开源项目SDK&#xff1a;https://github.com/mingyang66/spring-parent 个人文档&#xff1a;https://mingyang66.github.io/raccoon-docs/#/ Maven Wrapper是一个小脚本和库&#xff0c;它允许你再没有预装Maven的情况下构建Maven项目。通过Maven Wrapper项目的构建环境可以变…

C# 启动exe 程序

(1) publicbool Start () System.Diagnostics.Process process new System.Diagnostics.Process(); process.StartInfo.FileName "iexplore.exe"; //IE浏览器&#xff0c;可以更换 process.StartInfo.Arguments "http://www.baidu.com"; process.…

代理模式--cglib动态代理

1.介绍 cglib (Code Generation Library ) 是一个第三方代码生成类库&#xff0c;运行时在内存中动态生成一个子类对象从而实现对目标对象功能的扩展。cglib 为没有实现接口的类提供代理&#xff0c;为JDK的动态代理提供了很好的补充。 2.JDK动态代理与CGLIB动态代理对比 JDK…