泛型图像处理库

papercrane 2003-12-04 07:14:40
(延续6月housisong在C++泛型技术版的帖子)

https://sourceforge.net/projects/gill/

泛型图像处理库(GILL)是主要以计算机视觉为主的图像处理架构,基于C++泛型技术,可移植到几乎任何提供C++编译器的平台上。GILL提供了一个简单、高效、可扩展的方法,以便在不同的环境中灵活使用按照GILL架构开发的算法,或者开发全新的算法,同时获益于上述的优点。另一方面,GILL帮助您建立自己的图像处理库。现在,把现有算法按照GILL架构改写的繁重工作或许是个主要问题,然而重写能够从架构中获得最大的力量,就像C++ STL所做的那样。
GILL由三部分组成:协议、镜子、算法。协议规定图像表示的接口,图像表示可以是图像数据容器或者读写图像数据的途径(API、封装类、组件对象等);镜子遵守协议,代表一个函数,对图像表示作一定的变换后输出;算法根据协议对参与算法的对象进行访问,从而实现自己的逻辑。
算法作为整个体系里面具有最大价值的方面,被赋予最高的重视。架构的目标是使得花在上面的额外开销最小,包括重写、效率、移植调试和理解。
协议定义了数字图像处理和计算机视觉算法的数学抽象,它是抽象算法与具体数据交互的唯一标准。算法可以规定参与算法的对象实现的协议,而不能规定具体的对象。这种透明性是GILL获得可扩展性的来源。
镜子是连接具体图像表示对象和算法的媒介,面对不同环境时实现不同的配接功能,因为它能表示一个变换函数,所以也是实现数字图像处理算法的载体。

讨论过的问题
1. 现有的图像处理计算机视觉库有什么问题?
2. 一定得用泛型吗?
3. 为什么现在没什么算法可用?
4. 协议为什么是现在这个样子?
5. 效率如何保证?
6. 能不能跟现有的库混合使用?

欢迎讨论 :)
...全文
233 30 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
30 条回复
切换为时间正序
请发表友善的回复…
发表回复
e_feeling 2004-01-10
  • 打赏
  • 举报
回复
gz
8alang8 2004-01-06
  • 打赏
  • 举报
回复
关注~
jpzhu 2004-01-06
  • 打赏
  • 举报
回复
谢谢楼主的热心回复,我会关注这个工程的。
foreverfresh 2004-01-02
  • 打赏
  • 举报
回复
谢谢楼主的大作,支持
papercrane 2004-01-01
  • 打赏
  • 举报
回复
to jpzhu:
1.关于视频处理,你说得没错。目前压缩技术在视频数据中的广泛应用,使得帧间联系并不是一个简单的随时间变化而变化的函数,也就是说,除了把gill的图像概念I(x,y)扩展到F(x,y,t)之外,还有更广阔的天地。MPEG4中包含的基于内容检索的功能,将把内容、关键帧等概念作为划分视频数据的单位。当然,简单的扩展或许对付简单的视频处理还可以。
2.前面的讨论中已经谈到了,现在再强调一次,就是为了解决“接口排他”,达到比较高度的可复用能力(当然是泛型的框架之内),这个才是主要的目的,换言之,是在复用性方面下功夫。前两天csdn有介绍MDA的文章,各位不妨读一下,套用MDA的模型,gill框架下的算法可以比作pim,用具体protocol和mirror具现算法可以比作把pim转化为psm,c++编译器可以比作是从psm翻译成code的工具。
jpzhu 2003-12-31
  • 打赏
  • 举报
回复
有两个问题项要请教楼主:
1 图像处理和视频处理关注的焦点不同,一个在于静态的图像,而另一个关注图像间的变化联系。而gill的这套框架,是不是有扩展的可能,进而满足视频处理运算的需求?
2 这套框架在实际的商业开发,调试和测试中,能够起什么积极的作用?在我看来,通过gill,可以把运算模块清晰的组织起来,并把数据格式转换的工作,留给mirror来完成。这样就有可能在一个成熟正确的算法原型中,加入以及替换为自己的模块,逐步优化?
我对dsp和图像处理不是很熟悉,提的问题难免外行了,望楼主指正。
mattus_zhao 2003-12-30
  • 打赏
  • 举报
回复
谢谢,正在研究中。
foreverfresh 2003-12-29
  • 打赏
  • 举报
回复
请问我用opencv开发图象处理的程序,要做些什么准备,怎样着手呢?请有经验的大牛/大虾们帮帮忙吧
papercrane 2003-12-29
  • 打赏
  • 举报
回复
第二部分:

2. GILL为何被设计成这样
起步时有清晰目标是好事情,但在我们这里却不见得十分好。:(
在CSDN (http://www.csdn.net)上讨论时,我们遇到不少观点,比如,人们较为关心这个库能提供什么算法,或者现有的库很不错了,又或者是鼓励的话语,等等。面对如此多的意见,我们三个成员可以没经过什么讨论就达成一致的确有些奇怪。唯一的混乱是papercrane以非常隐晦的方式问Housisong能否接受GILL所需的某种概念,然后后者答曰你说的我早说过了(比较令人尴尬:))。从ajoo那里我们得知这个概念可称作“protocol”,为ajoo所提出。于是,我们顺理成章的决定用protocol来描述前面提到的三块基石的接口。比较幸运的是我们没有一开始就纠缠于实现什么算法,免于陷入不必要的争吵中。这一切过于顺利,使得papercrane怀疑很快就会有麻烦降临。
下一步该如何?Housisong建议采用protocol canvas,那时用的是另一个名字,而papercrane提议用protocol grid。当然了两个人都认为自己的protocol是最佳方案。现在我们知道每个方案都有优缺点,不过显然当时我们没有意识到。当时的讨论集中于一件事上:应该支持非原始类型(NonPOD)的图像像素吗?
这是个决定性的结论。如果回答是,canvas在进行像素写入时深复制的花销不少。尤其在像素类型拥有成员变量和成员函数,并且这个成员通过像素存取以可写的方式访问成员时,深复制就会发生。例如,读取像素对象,改写成员变量或者调用改写对象的成员函数,然后写回原先的像素中。Grid呢?它可以轻易的得到像素对象的可写引用,可以直接在上面作改写而不会付出额外开销。但如果回答否,canvas和grid看上去就没什么差别,直到后来Housisong发现了grid的缺点。
Grid的自由之处也就是它的缺点。Grid如何能做一些事情:它们必须依赖已经完成的改写动作?请注意“已经完成”的含义。当grid的像素访问函数返回时,它并不了解改写动作是什么。而当改写动作完成时,grid唯一能有所动作的方法是利用grid像素访问函数返回值的析构函数。这时候存在着一个限制:析构函数中不能抛出异常。事实上,根据改写动作所作的事情中包含抛出异常,这样合理吗?无可非议,然而现在被grid所禁止了。但是对于canvas,这一切显得相当自然且没有难度。
与此同时,ajoo提出的观点使得争论更显千头万绪,无从入手。他提出protocol sheet。Sheet可以通过行或列来访问。人们可以先指定行/列,再指定行/列中的哪一格。换句话说,坐标分量x、y可以分离指定。当确定具体哪一格时,sheet便提供如canvas一样的get/set接口。
OK,现在三种protocol混成一团麻了。事实上,ajoo当时提到应该尽可能减少限制,细节可以日后慢慢再谈。不过当时的讨论充塞了太多东西,把我们弄胡涂了。我们都专注于针对效率、优雅和实用的解决办法。
不管怎样,为了找出哪种提议最好,我们还是作三个假设:如果分别选择canvas、grid和sheet,接下来会看到什么事情?首要问题就是配接。实际上,即使没有这三个提议,世上各种图像表示的接口都是不一样的。任何一种提议都得处理这些差异,或者说都需要配接器。经过针对效率和复杂性的深入讨论,我们发现其实仔细设计的话,配接过程只有可忽略的额外开销。
这就对了,既然接口之间转换没有值得一提的额外开销,——自然也包括那三个提议——那么为何不把三个protocol都包括在新的库中呢?算法以canvas、grid或者sheet任一个作为protocol都可以,不同protocol的图像大可以使用配接器来满足调用接口。既然没有全天候最佳,自然需要灵活一些的方案。算法可以选择对它而言最好的protocol。
其时新的库名为GILL,已经放上SourceForge了。当papercrane根据上述讨论结果,开始把canvas和sheet加入GILL时,他发现了一个未解决的问题,之前提到过但当时忘记了。讨论不同protocol之间配接时,我们忽略了一点:改写成员变量和调用改变成员的成员函数(简称成员改变)。
protocol canvas和sheet没有像素数据的直接引用。它们只能先调用“get”把数据读入一个临时对象,在此对象上做完成员改变,再调用“set”把数据从临时对象写回像素中。举个例子:
template<class Im>
void f(Im im)
{
// …
T tmp = im.get(x,y); // 把像素数据读入对象tmp
tmp.foo(); // foo函数会改写tmp
im.set(x,y,tmp); // 从tmp中写回im
}
另一方面,protocol grid具有像素数据的直接引用,如同基于组件架构中的“属性”一般。那实现成员改变可就相当自然了。例如:
template<class Im>
void f(Im im)
{
// …
im(x,y).foo(); // 简洁快捷!:)
}
无论我们选择那种做法,都得兼容别的protocol。例如,如果选择第二种做法,具有canvas protocol接口的图像,被配接成为grid接口,也得适用于这种做法下的算法,不可出现似是而非的结果,比如说成员改变只是在临时对象上,而不是想要的像素数据上产生了效果。那么,我们该如何设计算法f,使之无需考虑各protocol在此问题上的差异呢?
如果跟从canvas用get/set包起来的代码模式,当遇到本质上以protocol grid为接口的图像时就会产生额外开销,这些成员改变本来无需get/set的。
如果跟从grid的代码模式,问题就在于如何在foo调用完毕后调用“set”?很不幸我们不能依赖foo本身,那是像素类型所控制的。想象im(x,y)返回了一个对象,这个对象的析构函数在foo之后调用,看来是个放置“set”的好地方……等等!还记得讨论grid的缺点时提到这会带来什么问题吗?是的,未定义行为的陷阱:“set”或许在析构函数抛异常。
看来简单的跟从现有表达方式是无法解决问题的。当时GILL不得不暂时集中于解决这个问题,直到ajoo提出一个方案,成为protocol mutator。
Protocol mutator把成员改变和具体protocol的耦合分离开来。Protocol canvas/grid/sheet决定如何给出一个名为mutatee的可以改写的对象,在此对象上成员改变能够真实的作用在原先的图像上。给出这个对象之后,mutator才能够对其施加具体的改变。通过这样的手段,成员改变和具体protocol相互没有依赖。如何给出可改写对象的策略可以附在protocol canvas/grid/sheet中。每个protocol都有自己的策略,称为mutatee_adaptor,这东西接受图像对象和mutator对象作为参数,其中封装了调用的顺序和可改写对象如何产生的细节以及差异。下面是一个例子:
template<class Im>
void f(Im im)
{
// …
M ma = im.get_mutatee_adaptor(); // mutatee_adaptor
Mutator mb; // mutator
ma(im(x,y),mb); // 收集mutatee和mutator
}
// …
struct mutatee_adaptor
{
template<class R, class P>
void operator()(R& v, P& p)
{
T obj = …; // 如何给出可改写对象?
p(obj);
// 还有什么要对obj做的?继续做
}
};
补充完这一点,GILL就没有什么太大的问题了,当时发布了稳定版本0.0.2。
papercrane 2003-12-29
  • 打赏
  • 举报
回复
贴一个翻译好的文档,有助于了解GILL是什么。

GILL设计与演化
作者: ajoo,papercrane,Housisong
最后更新: 2003.12.29
1. 为何需要GILL
现有的图像处理(简称IP)或者计算机视觉(简称CV)库几乎都拥有自己的图像表示。这些库根据各自的图像表示来设计IP/CV算法。可以想象,没有一个库可以覆盖所有IP/CV算法。它们之间可以有重叠和不同的部分。有时混合不同的库开发IP/CV算法是相当实际和频繁的。
然而,复用现有的算法时不同的图像表示会带来麻烦。我们需要在来自不同的库算法之间把数据表示形式转来转去,这样时常导致复制和资源管理开销。这些额外的开销会在实时应用中降低效率,或者在小内存应用中导致完全的失败——没有足够的资源用于复制。同时,如果图像表示在设计时不能做得很好,或者与未来需求发生冲突,那么据此设计的新算法会陷入混乱。我们没法对每件事都预料得那么准确。被忽略掉的问题不仅影响当前工作,还影响到已经完成的代码。这使得做改进不太容易。
根据IP/CV算法的本质,我们需要一个更灵活更可复用的库,同时这个库应该能方便、高效和可以扩展地开发新算法。换句话说,这应该是一个架构,或者是开发库的库。
为了达到这个目标,我们先探讨IP/CV算法与其他算法的区别。CV算法可以分为三个层次:低层处理包含原始数据的粗略处理(也就是大多数的IP算法);中层处理提取元素以及与图像的关系;高层处理主要是对上述关系的认知和理解。这显示CV算法中“读”相对来说比“写”更频繁和重要一些。IP/CV算法包含信号处理、模式识别、人工智能等知识,所以通常需要复杂的数学运算,流程图往往适合用来描述算法。也就是说,IP/CV算法相对来说较抽象。
实际应用中,IP/CV算法的功能较其效率通常更有价值一点。但是在不同的环境中,例如实时和小内存,诸因素的平衡也是值得考虑的。硬件固化重要算法、平台和数据源差异、动态/静态环境常常使得系统瓶颈到处转移。开发者不得不为许多设计算法时难以考虑到的问题做抉择。
由此,新的库应该自身可以或者帮助开发者“一次编写,到处可用”。诸因素平衡的难题应该留给解决差异的人,而不是算法设计者本身,因为他并不能预料到是什么差异。换句话说,平衡问题不应该由算法解决。我们需要“配接器”来做这项工作。配接器可以看作是一个图像,算法要处理的对象,里面隐藏着解决平衡问题的方法。这样算法保持着数学原理上的纯粹形式。面对不同环境,开发者只需编写配接器而不是算法。
综上所述,新的库由三块基石组成:
* 独立于图像表示
* 抽象描述
* 配接器对其透明
算法必须处理图像,但是不应该依赖图像具体是什么。图像表示的差异对于算法来说仿如无物。相应的算法需要足够抽象。如果能如此,良好设计的配接器能够充当图像表示的角色与算法合作,这时候算法是看不到配接器的,只能看到抽象的图像表示。
当这个架构完成时,IP/CV算法,特别是巨大、复杂的算法不需要被重写,为新需求而做的唯一事情是制作配接器。如有另一个需求,就制作另一个配接器。
这就是最终的目标。
papercrane 2003-12-21
  • 打赏
  • 举报
回复
to everyone:
读过GILL之后有兴趣或者觉得有什么不吐不快的话,不妨加入这个team,无论是开发、测试、文档还是仅仅讨论,我们都是热切欢迎的。
值得强调的是,GILL的"LL"是libraray of library的意思,GILL面向库开发者的成分比面向库使用者的成分更多一点。所以遇到下面这些问题时:
1.算法的接口不友好:我个人认为是属于trivial问题,——比起算法实现,实在是小case,根据具体环境具现化,再包装个外壳做invoking forward就行了。
2.泛型很难懂:er~~~~,这个,您就当作是苦口良药吧。
3.对现有算法的兼容性:从机制上来说,基本上不可能有。如果各位想在这点上狂踩GILL的话,我只有把stl也拉来垫背了。

to eastsun:
没法啦,你看看opencv的change log最后一行是什么时候添加的:)

to mattus_zhao:
计算机视觉,透过图像表示这一层之后,要面对的是庞大的数值计算和人工智能,图像不过是个幌子罢了。要么让泛型在这一步刹住,老老实实的按照已有库的接口要求来布置数据,要么就让泛型进行到底,——我已经在准备GMLL了,这个M是矩阵的首字母。然而,优化要求是泛化的大敌。谁能保证泛型参数的数据布置符合优化要求吗?traits?等着看tag满天飞吧。
mattus_zhao 2003-12-20
  • 打赏
  • 举报
回复
毕竟现在使用 C 语言的视觉库还是很多的。
在视觉库里面使用泛型编程对于代码重用等等非常有好处。
我想我得花点时间去研究研究。
mattus_zhao 2003-12-20
  • 打赏
  • 举报
回复
To papercrane:
是呀,Intel 把它的 IPL 贡献给了 OpenCV , 所以 OpenCV 很多地方是针对 IPL 的封装也就不奇怪了。
的确,ImageMagic 支持非常多的图像格式(大概几十种),VisSDK 专门提供了对它和 IPL 库的支持。不过,一般的应用 OpenCV 都足以应付了。
我也主要是基于 VC6 在做开发,同时使用 GNU C++ ,用 Visual.net 就是想看看它的编译器如何。感觉对 ISO C++ 标准的支持更好了。
我会去详细看看 GILl 库的,谢谢。
eastsun 2003-12-20
  • 打赏
  • 举报
回复

OpenCV简直是披着C++外衣的C,估计是一个过于古老的程序员做的整体设计。

感觉OpenCV整个架构的持续抽象的能力很有限。估计C程序员会比较欢迎。

但对于研究新算法,不那么友好。而且其源码的可读性比较一般。


papercrane 2003-12-19
  • 打赏
  • 举报
回复
to mattus_zhao:
过奖了,当时简单看了一下而已,其实我从来没有用过VisSDK,有什么不对的地方还请指正。
从图像格式的支持上似乎ImageMagick更多(我不敢说好不好,没用过)一些。而IPL在低层上做得很好,OpenCV不少地方干脆就是对IPL的API进行封装。
vc6对C++标准支持得确实不太够,按我开发时的感受来说,因为不能偏特化,结果ptr_fun不能支持返回void的函数指针,只能用一个mpl的手段来解决gill/base/algo.h中for_each配接器的问题,您不妨下载GILL看一下。我的意见是,既然连Loki都能port到vc6,那些问题算是小case了。因为目前不少应用都是在vc6上做,只能让这个遗憾继续一段时间了。
如果您认为像素类型的可定制是一种策略(policy)或者演化(evolution)的话,那么我想说的是,GILL是针对更多更广泛的策略和演化,例如图像数据源(文件格式/视频/网络/数据库)、时间-空间平衡,乃至算法的要求(同态滤波的例子)等等。
mattus_zhao 2003-12-17
  • 打赏
  • 举报
回复
papercrane对这方面还是比较熟悉的嘛。
我最早的时候用过VisSDK做过一些开发,就像你说的一样,涉及到具体的算法时都需要自己去设计,只不过底层的东西建立在VisSDK上面。而且,我发现微软的研究小组似乎已经很久没有更新这个视觉库了,也许他们也不太满意。他们使用时读入图像的接口也推荐使用象ImageMagic等库。所以后来我也改用OpenCV了。
不过我觉得通过泛型来建立视觉库确实很不错,至少在象素的类型不受限制。不过我曾经用Visual C++ 6.0 做过一些测试,发现它的编译器对模板的支持不太好。但是用Visual C++.net 就没有问题。用GNU C++ 就没有问题。

papercrane 2003-12-16
  • 打赏
  • 举报
回复
个人的观点是,就计算机视觉应用而言,使用现成算法的话,opencv要好一些;自己开发算法的话,VisSDK还不错。
foreverfresh 2003-12-15
  • 打赏
  • 举报
回复
VisSDK 好像没有提供什么图象处理得基本算法,做图象识别是不是OpenCV好些呢?
papercrane 2003-12-13
  • 打赏
  • 举报
回复
to foreverfresh:
你是说sourceforge吧,发布了stable demo 0.0.2和unstable demo 0.0.5。stable demo 0.0.2基本上是稳定的了,提供了整个架构和文档,至于人气,那么多有名的开源项目,一般人也不会怎么留意到的。
foreverfresh 2003-12-12
  • 打赏
  • 举报
回复
我在做图象识别,用哪个库好些,望大牛推荐
加载更多回复(10)

4,499

社区成员

发帖
与我相关
我的任务
社区描述
图形图像/机器视觉
社区管理员
  • 机器视觉
  • 迪菲赫尔曼
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧