较难的问题(对黑白图像进行适当的处理,得出一些色块的大小和位置)(100分)

  • 主题发起人 主题发起人 nhuangjr
  • 开始时间 开始时间
N

nhuangjr

Unregistered / Unconfirmed
GUEST, unregistred user!
有一幅黑白图片,上面有一些黑块,背景一白色为主(不纯)。
有兴趣的大侠可以到 luckrong.go.163.com 处下载样例,或我直接发给你们。
现在想知道由上到下各黑块的起始横坐标和大小。

我觉得这个问题的难点是:
1、怎样去掉背景的杂色;
2、怎样区分连在一起的黑块。

各位大侠,帮帮小弟啊!

分不够可以加啊!
 

怎么搞得我是给300分的啊,怎么变成100分的呢?
 
首先通过一个阈值将图象二值化,然后通过下面的程序可以获得各个块的大小以及
最小矩形框。

type
TCell = record
Left, Top, Right, Bottom: Integer;
Size: Integer;
end;

function GetCell(Bmp: TBitmap; x, y: Integer): TCell;
const
dx: array [1..4] of Integer = (-1, 0, 1, 0);
dy: array [1..4] of Integer = ( 0,-1, 0, 1);
var
Ptr: PByteArray;
Cell: TCell;
i, nx, ny: Integer;
begin
Ptr := Bmp.ScanLine[y];
Ptr[x] := 0;
with Result do begin
Left := x;
Right := x;
Top := y;
Bottom := y;
Size := 1;
end;
for i := 1 to 4 do begin
nx := x + dx;
ny := y + dy;
if (nx >= 0) and (nx < Bmp.Width) and
(ny >= 0) and (ny < Bmp.Height) then begin
Ptr := Bmp.ScanLine[ny];
if Ptr[nx] = 0 then begin
Cell := GetCell(Bmp, nx, ny);
with Result do begin
if Cell.Left < Left then Left := Cell.Left;
if Cell.Right > Right then Right := Cell.Right;
if Cell.Top < Top then Top := Cell.Top;
if Cell.Bottom > Bottom then Bottom := Cell.Bottom;
Inc(Size, Cell.Size);
end;
end;
end;
end;
end;

function CellToString(Cell: TCell): String;
begin
Result := Format('(%d, %d) - (%d, %d): %d',
[Cell.Left, Cell.Top, Cell.Right, Cell.Bottom, Cell.Size]);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
Bmp: TBitmap;
Ptr: PByteArray;
i, j: Integer;
Cell: TCell;
begin
Bmp := TBitmap.Create;
try
Bmp.LoadFromFile('d:/myfiles/Cells.bmp');
Bmp.PixelFormat := pf8Bit;
for i := 0 to Bmp.Height - 1 do begin
Ptr := Bmp.ScanLine;
for j := 0 to Bmp.Width - 1 do
if Ptr[j] = 0 then begin
Cell := GetCell(Bmp, j, i);
ListBox1.Items.Add(CellToString(Cell));
end;
end;
finally
Bmp.Free;
end;
end;

 
JohnsonGuo兄来帮忙!太好了!
你这段程序我在“粒子计数”问题中已经看到了。很好。
问题是:
1、图像二值化的时候阀值不好选,图像中有些色块的灰度与背景相同,不能区分。
我的做法是:先对图像锐化,再二值化,有时候效果不错。
2、关键问题是:色块分离,我要两行相贴的色块相分离,色块原则上是一行一行
每行色块代表不同的信息。但色块的顺序是随机。
我的想法是:在他们之间划分割线,现在正在做实验。
 
有没有伪彩色编码的算法?
或者有没有相关的软件?
 
首先考虑到图象可能并不是真正的灰度图,
可以通过图象处理软件,或是自己将图象转变为256级灰度图。
然后作出图象的直方图,你会发现直方图中,会有左右两个峰点,
在中间有一个谷点,你就取谷点作为阈值,这样获得的二值化图象会很好的。

或者你可以作一个交互界面,让用户通过选择不同的阈值,
来获得二值化图象,直到取得某个阈值时效果最好的时候再进行色块适别。
 
JohnsonGuo兄:
不知道你有没有下载我的样例图片,由图片可以看出有些色块的灰度比某些地方
的背景灰度还要小,所以用一般的阈值法应该是不能用的(不能丢失色块的啊)。
不过我也想知道怎样可以作出图象的直方图,有现成的程序吗?
JohnsonGuo兄,你能帮我想一想第二个难点吗?

 
我已经下载了你的图片,但我没有看到比背景灰度还要小的色块(可能我的近视太利害了,
呵呵)。
如果是这种情况,那么其直方图应该存在3个峰点,2个谷点,就取个谷点作为阈值,
把阈值之间的颜色视为背景,两则的颜色视为前景应该可以。
至于直方图,就是对图象中的颜色进行统计罢了,把图象中各级灰度进行统计,
然后以灰度级作为x轴,各个灰度级上点的个数作为y轴所作出的图象就是直方图。

至于连在一起的色块,你得定出一个划分的标准,才能给出程序区分的准则啊。
如果人眼都分不出连在一起的色块的实际上是多少个细胞,那么用计算机进行适别
是毫无意义的。
 
图像的二值化我已经基本解决了,现在把问题集中在的二点。
其实,那些色块特点是很明显的:
1、他们的厚度基本上是相等的;
2、他们原则上是每行只有一个色块;
3、每个色块基本上是平行的;
4、他们的分布基本上是:靠左的,中间的,靠右的。
区分的准则是:
1、色块的厚度接近正常色块厚度两倍的要分开(多数情况下,
分开的两各色块长度是不同的,但也有能是相同或接近的);
2、头尾相接的要分开。
我给你发一幅经过处理的图像吧。
 
我用下面的程序分析黑白图像中的黑块的位置和大小,但是得出的并不正确。
希望大侠们帮我看看程序错在那里。

procedure AnalyzeBlock(Bmp:TBitMap);
//Bmp图片中右上到下列有一些大概是长方形的黑块,这些黑块有可能上下相连的;
//现在要把每个黑块的位置和长度分析出来。

//算法是:
// 一行一行的扫描图片;
// 找出每行中连续黑点的位置的长度,如果该行的连续黑点的位置的长度与
// 上一行的相近则说明他们是同一色块,忽略不计,否则,它是新的黑块的
// 记录下来;
//

var
P1:PByteArray;
i,j,j1:Integer;
preSx,startx,starty,endx,endy,preL,length,jiange,lines:integer;
b:Byte;
Begin
Form2.ListBox2.Clear;
startx:=-1;//黑块横坐标
starty:=-1;//黑块纵坐标
endx:=-1;
length:=0;//黑块长度
jiange:=0;//黑点间隔,用于判断黑点是否干扰点
lines:=0;//黑块总数
for i:=0 to Bmp.Height-1 do
begin
P1:=Bmp.ScanLine;
j1:=0;
startx:=-1;
endx:=-1;
length:=0;
jiange:=0;
for j:=0 to Bmp.Width-1 do
begin
//寻找第一个黑点
if (P1[j1]=0) and (startx=-1) then
begin
startx:=j;
jiange:=0;
Inc(j1,3);
continue;
end;
//计算黑点的长度
if (P1[j1]=0) and (startx<>-1) then
begin
length:=length+1;
endx:=j;
jiange:=0;
Inc(j1,3);
continue;
end;
//计算白点长度
if (P1[j1]=255) and (startx<>-1) then
begin
jiange:=jiange+1;
end;

if jiange>9 then
begin
if length>18 then //找到了一个黑块
begin

break;
end
else
begin //干扰黑点
startx:=-1;
starty:=-1;
endx:=-1;
endy:=-1;
length:=0;
jiange:=0;
end;
end;
Inc(j1,3);
end;

if (length>18)and((abs(preL-length)>18) or (abs(preSx-startx)>50)) then
begin //增加黑块
Form2.ListBox2.Items.Add('('+inttostr(startx)+','+inttostr(endx)+','+inttostr(i)+')'+inttostr(length));
lines:=lines+1;
end;
preSx:=startx;preL:=length;
end;
Form2.ListBox2.Items.Add(inttostr(lines)+'行');
end;
 
让我想想,我考完试答复你。
 
问题的关键是决定色块的高度。

首先把图像中的各个色块找出来,把每一个色块上的点按横坐标从小到大排序。
那么,对每一个色块上的每一个横坐标,可以计算出色块在该横坐标上的高度。
对高度进行统计,作出其直方图。
可以预期,
1。直方图中,会周期性地出现峰点;
2。第一个峰点,通常会最高;
可以用下面两种方法来求色块高度:
1。取第一个峰点的横坐标为整幅图象的色块平均高度。
2。使用最小二乘法。

BTW:放假了,要回家过年了,家里的上网条件并不理想,所以有什么问题尽量用
E-Mail交流,祝好运新年快乐。
 
JohnsonGuo兄:恕小弟愚钝,看不懂你的方法,小弟的图象处理太差了,你能不能把程序
写出来啊。

其他大侠怎么不来啊,是不是分太少了。
我现在郑重声名:
这个问题的分值是300分,不够的可以再加!
希望各位大侠多来发表高见。
 
快来人阿!!!!!!!!!
 
举个例子吧,下面的色块
*****
***********
**** **
**
高度为1,2,3,4的列分别是4,3,2,2
把这些数据作出统计图,如下
^
| *
| * *
| * * * *
| * * * *
+-------------->
1 2 3 4
(当然这个数据不能当真)
按着上面的方法作出统计图,就会有所发现,你先试试吧。
 
JohnsonGuo兄
我觉得你的方法不是很行啊,不过不管怎么说,还是很感谢你的帮助!

算了,结束了!
 
后退
顶部