更全的杂志信息网

基于TI 6678多核DSP的OpenCV并行优化*

更新时间:2009-03-28

1 引言

OpenCV是一个广泛应用于工厂产品检测、医学成像、信息安全、用户界面、摄像机标定、立体视觉、机器人视觉的开源计算机视觉库[1]。在计算机视觉有关的事务处理上,OpenCV已经成为一个实际上的标准库工具[2]。目前全世界有4.7万OpenCV社区,OpenCV官网的下载量超过1 400万[3]。OpenCV采用C/C++语言编写,可以运行在Linux、Windows、Mac、Android、IOS等操作系统上,同时提供了Python、Ruby、Matlab以及其他语言的编程接口,因此OpenCV具有非常强的平台适应能力和广泛的应用空间。

数字信号处理器DSP(Digital Signal Processing)广泛应用于各类工业领域和军事装备领域,国内外许多研究机构和厂商都致力于将OpenCV移植和应用在各种嵌入式平台,以便结合嵌入式平台体系结构特点发挥出OpenCV的强大功能,拓展嵌入式图像处理的应用。但是,目前针对DSP的OpenCV移植和优化实现进展缓慢。例如,TI公司是当前DSP领域的领跑者,但目前仅有TI ARM® Cortex®-A系列芯片提供了对OpenCV 3.1的支持[4],并且仅支持在ARM平台的Linux系统环境下运行[5],通过OpenCL支持将计算任务分发到DSP上间接实现OpenCV的嵌入式应用[6],目前TI的这种解决方案中并没有做DSP端的优化。国内2008年出现过一个针对TI DSP移植OpenCV的开源项目EMCV[7],但是到目前仅仅实现了少量OpenCV基本数据结构,实际实现移植的功能函数很少。成都芯本智科技有限公司也在做相关工作,目前正在网上召集全球范围内的合作者构建一个能在DSP上运行的图像处理库CVD(Cmputer Vision on DSP),但是工作刚刚起步,宣传网站上没有任何进展[8]

造成OpenCV直接移植到DSP难度大的原因在于OpenCV的发展是从Intel平台开始慢慢拓展的,发展至今在嵌入式平台的应用也多是在嵌入式Linux上实现。目前OpenCV的维护人员也仅提供OpenCL的异构并行来拓展嵌入式的应用,直接移植OpenCV到DSP的底层支持少。同时OpenCV是一个庞大的运行库,依据具体的DSP平台特点针对具体的算法和功能函数进行优化工作投入和资源耗费非常大。

本文通过分析OpenCV的代码层次和构成、不同函数共性及其并行方法实现,结合TMS320C6678(以下简称TI 6678)对C和C++的支持和丰富的底层库实现,分析了移植OpenCV到DSP上的一般方法和约束条件,提出编译提示下底层库补全与功能裁剪的一般方法,实现了直接在DSP上移植运行OpenCV图像处理库。摆脱目前嵌入式OpenCV对Linux的依赖,使得OpenCV的嵌入式应用可以在更多嵌入式平台上运行成为可能。同时,本文分析发现一类OpenCV库函数在TI 6678上运行时自动分配空间的数据存储不合理引发运行效率低下的问题,提出针对这类函数进行存储搬移改造和DMA优化的一般方法,用共性问题的优化来提升大型库代码优化效率,最大效率提升可达3.6倍。针对TI 6678特点以及对OpenMP支持的特点,本文分析了OpenCV在OpenCL上支持的200多个可异构并行的功能函数在单个多核芯片上可以用OpenMP并行替代的一般方法,通过OpenMP并行改造实现了多种OpenCB库函数在单个多核DSP芯片上多核并行,对于现在仅有的异构SoC(System on Chip)下通过OpenCL分配任务到其他DSP芯片计算的OpenCV嵌入式并行解决方案而言是一种拓展,扩展了OpenCV在多核嵌入式芯片的应用 。相对移植后进行数据流优化和DMA优化的单核运行性能,本文并行改造的这类库函数8核运行加速比达到2.55~7.06。

草地理论载畜量是合理制定家畜补饲方案的基础,估算理论载畜量可以为合理利用草地,有效监测草地退化,实现草畜平衡、防治草地退化、保护草地资源提供直接依据[40]。林莉等[41]采用体外产气法测定草地载畜量,结果发现产量载畜量小于营养载畜量,DCP载畜量大于ME载畜量。这与此次DM总载畜量高于ME总载畜量和DCP总载畜量的研究结果不同,试验采用的ME载畜量计算方法没有牧草消化率试验,得到的理论值偏大。郝力状等[42]采用人工瘤胃模拟培养计算产气量和消化率,对三江源区枯草期嵩草草地载畜量进行研究,发现营养载畜量均小于牧草产量载畜量,ME载畜量大于DCP载畜量而小于DM载畜量,与本研究结果一致。

2 OpenCV的DSP单核移植和优化

TI 6678是TI在2010年推出的一款多核高性能处理芯片,推出时性能和功耗表现超越了业内所有其他DSP[9]。对比国内近几年的DSP芯片,TI 6678在性能上仍然具有比较强的优势[10],同时该芯片在目前仍然具有优秀的低功耗表现[11],因此选择TI 6678作为OpenCV的DSP移植平台对DSP图像处理应用具有较强的代表性。OpenCV能否在一个平台上运行依赖底层基础运行库以及C和C++编译的支持,TI提供了丰富的底层运行库支持,支持C和C++的编译,所以OpenCV可以在较小的修改情况下方便地实现OpenCV的移植。在移植OpenCV过程中依据编译报错提示,分析发现主要的问题来源是一些TI没有支持的功能函数。这是由于不同平台相同的底层支持库实现的具体函数种类的差异,对于重要的函数功能,需要做相应的补充实现或者使用类似功能替代实现。而对于其中包含的只适用于PC平台的输入输出功能以及其他TI底层无支持的外设通信的代码需要进行裁剪。依据上述移植分析和策略,本文已经将OpenCV 2.4.9以及OpenCV 3.0主要图像处理功能在TI 6678上移植实现,生成了可以在TI 6678上直接使用的OpenCV底层静态链接库,依托这个支持库,编程人员可以在TI 6678上使用绝大多数OpenCV功能函数进行图像处理开发。实现TI 6678上独立运行OpenCV的意义在于:证明了在不依赖目前常用的操作系统情况下,在DSP上独立运行OpenCV是可行的。横向上这将极大地扩展OpenCV可以应用的DSP平台,而不仅仅限于ARM系列或者ARM+DSP架构,纵向上可预知实现后续版本的OpenCV移植到DSP是可能实现的。而且这种直接移植可以灵活地开启编译优化选项进行优化,本文实现的OpenCV静态支持库均开启了O3优化。

对移植到TI 6678后的OpenCV运行时通过跟踪调试程序,发现对于存在buf结构的这类功能函数在执行过程中会用一个循环将源Mat矩阵的数据分块搬移到buf结构的缓冲区进行处理,有可能在buf内进行多次处理,即buf空间内也存在搬移,在缓冲区内处理结束后会放到目的Mat区域。由于处理图像时OpenCV的Mat变量矩阵多数情况下都比较大,需要放置在片外DDR空间,因为代码链接器自动排布机制,处理过程中的buf结构也将被编译器放置到DDR空间,如图1所示。这种情况下,这类算法会将数据在DDR中来回地搬移,造成了程序运行效率的下降。

  

Figure 1 Data streams under automatic distribution图1 自动排布情况下的数据流

以矩阵的算术运算为例,其底层依赖的OpenCV函数为arithm_op,某些输入参数情况下会导致在如下所示的伪代码执行:

_buf.allocate (buf_number*blocksize);//申请空间

源数据经过DMA放入L2SRAM,更改OpenCV代码中的buf变量指向的位置,用较小的代码修改代价改变后续一系列数据流向,执行等价效果如图2所示。数的处理被集中在L2SRAM中,从而达到加速的效果。

buf2=_buf+blocksize;

buf3=_buf+blocksize*2;

for(size_t j=0;j<total;j+=blocksize)

{

fun1(src,buf1,blocksize);/*源数据1经过fun1处理存入buf1*/

fun2(src2,buf2,blocksize);/*源数据2经过fun2处理存入buf2*/

fun3(buf1,buf2,buf3,blocksize);/*buf1和buf2数据经过处理存入buf3*/

萍乡春锣一般是由一个人演唱,艺人用红绸系上一个直径约为15公分的小锣鼓并在旁边别上一个锣槌,演唱者左手持鼓签,右手拿锣槌。在演唱的间歇中用鼓签、锣槌敲打出“咚咚咚呛|咚咚咚呛|咚呛咚呛|咚咚咚呛”的节奏型,并由此作为萍乡春锣的一部分。

fun4(buf3,dst,blocksize);/*buf3数据经过处理写回目的地址*/

DMA(temp1,src1);//数据搬移

本文针对运算过程中自动分配缓冲区进行分块计算的特点,在TI 6678的L2SRAM中单独划分出一片空间,使用 DMA方式进行加速。将OpenCV功能函数中具有这种结构的代码进行改造,代码修改如下所示:

_buf=L2SRAM_BUF;//修改buf空间指向

buf2=_buf+blocksize*2;

temp2=_buf+blocksize;

temp1=_buf;//用作数据搬移

(1)Cpv是指施工项目在考核期内,基于拟投入的安全成本,在确保计划安全保障水平的基础上安全成本的计划费用值。

buf3=_buf+blocksize*3;

重视培养学生的能力,一直是我国基础教育改革与发展的重要目标。对于能力的培养,既有一般目标,也有各自学科的特殊要求和特殊问题。教育不能只满足知识的传递,而是应该将重点放在提高学生能力的培养上,才能将“知识”转变为“智慧”,才是素质教育的应有之义。

for(size_t j=0;j<total;j+=blocksize)

{

通过程序跟踪,编译生成的代码会将bufMat放在相同类型的存储空间,对于一个1280*768的四通道图像,源Mat和目的Mat总大小超过4 MB,Mat矩阵无法放入TI 6678的片内存储空间,只能放置在DDR中,这时编译后的程序会将buf自动放置在Mat矩阵的后方。即从allocate语句开始,buf就被指向了DDR空间,之后的一系列循环计算全部都在DDR中执行。

DMA(temp2,src2);//数据搬移

fun1(temp1,buf1,blocksize);/*源数据1经过fun1处理存入buf1*/

fun2(temp2,buf2,blocksize);/*源数据2经过fun1处理存入buf2*/

fun3(buf1,buf2,buf3,blocksize);/*buf1和buf2数据经过处理存入buf3*/

所谓的妊娠合并糖尿病指的是:妊娠期间发现或发病的由不同程度糖耐量异常及糖尿病引起的不同程度的高血糖,其中有些患者在妊娠前便已经被诊断出患有糖尿病,在妊娠之后则有持续性加重的表现等[1-2]。为了研究妊娠与糖尿病的关系,从而提升临床治疗效果,本文在2015年12月-2016年12月间妇产科收治的80例妊娠合并糖尿病患者参与研究,探究其临床护理效果,具体研究内容阐述如下:

fun4(buf3,dst,blocksize);/*buf3数据经过处理写回目的地址*/

buf1=_buf;

  

Figure 2 Data stream after the transformation图2 改造后的数据流

但是,OpenCV实际的代码可能远比上述情况复杂,为了支持多种参数和变量类型的处理,底层的实现具有大量的分支。实际的buf使用如下所示,存在大量的分支处理,在这些分支中,buf位置的数据处理步骤数是不同的:

_buf.allocate(bufesz*blocksize+64);

buf=_buf;

if(cvtsrc1)

buf1=buf,buf=alignPtr(buf+blocksize*wsz,16)

if(cvtsrc2)

buf2=buf,buf=alignPtr(buf+blocksize*wsz,16)

本研究旨在探讨非英语专业大学生英语学习动机现状及负动机水平。具体研究问题如下:第一,非英语专业大学生在英语学习过程中是否存在普遍的负动机现象?第二,导致负动机出现的影响因素是什么?第三,大学生在英语学习过程中应采取何种动机调控策略?

wbuf=maskbuf=buf;

if(cvtdst)

buf=alignPtr(buf+blocksize*wsz,16)

if(haveMask)

maskbuf=buf;

植骨融合有利于重建胸腰椎结核手术患者脊柱的稳定性,减轻局部疼痛,减少术区假关节形成及内固定失败、断裂的概率。患者自身的条件,比如年龄和营养状况等可影响植骨融合及术后康复情况[6-7]。目前研究显示,在胸腰椎结核的手术治疗中,不同手术入路、内固定方式和植骨方式[8-11]均可以取得较好的疗效,且术后1年的植骨融合率均可达较高的水平,但术后早期(6个月内)的植骨融合率存在显著差异[3-4]。本研究通过分析术后早期植骨未融合组与融合组的各项资料,在调整了患者的年龄和BMI后,发现累及两个以上椎体、采用块状自体骨和术前血浆CRP高是胸腰椎结核手术患者早期植骨融合的独立危险因素。

另外,由于Cache的影响,如果buf位置的处理步骤只有一次,伪代码如下所示:

_buf.allocate(buf_number*blocksize);

2.1四组患者心脏结构相关指标比较:OSAHS患者组中,中度组与重度组患者的LVDD、LVDS、LA、IVS、LVPWD指标与健康对照组比较明显升高,差意有统计学意义(P<0.05),见表1。[3]

buf1=_buf;

for(size_t j=0;j<total;j+=blocksize)

由于在TI 6678上能够支持OpenMP[12],所以在无CUDA和OpenCL支持的情况下,在TI 6678上进行并行改造使用OpenMP是一个比较好的选择。从代码分析看,OpenCV使用OpenCL和CUDA以及OpenMP加速的函数功能是交叉的,例如OpenCV 3.0中,LUT函数同时支持三者加速,phase函数只支持CUDA和OpenCL加速,kmeans只支持OpenMP加速。所以,OpenCV在移植到DSP上后,由于不能支持OpenCL或者CUDA带来的并行计算支持的效率损失需要寻找替代方案来弥补,因而需要对原有只支持CUDA和OpenCL的OpenCV函数进行OpenMP改造。

fun1(src,buf1,blocksize);

两组患者住院期间,及出院后随访3个月,均未出现严重出血并发症。治疗组患者12例发生出血并发症(12/40),对照组患者11例发生出血并发症(11/39),两组患者出血事件发生率比较,差异无统计学意义(P>0.05)。

fun2(buf1,dst,blocksize);

}

实际的数据流就会如图3所示,源数据和目的数据在读写的时候会被Cache加速。这和本文的改造方案相比,实际运算的存储位置是相同的,只有在buf位置的计算较多的时候,本文的计算优势才会体现出来。因为若没有改造,buf内处理的次数增加会引起Cache不断替换,执行效率就会降低。

中国古典艺术批评中,微妙的“气氛”感,具体而言,还涵摄着多组“家族类似”的命题:气之浑成兴发,为元气;气之生动活泼,为气韵;气之流转为气脉,气之凝炼为气骨,气之舒展为气势,气之氤氲为气氛,气之沉淀排构,为气格等,兹不一一展开论列。

  

Figure 3 Once a buf processing data flow with Cache opened图3 开Cache情况下一次buf处理的数据流

3 OpenCV函数进行OpenMP并行改造的一般方法

OpenCV在功能函数中大量加入了对OpenCL和CUDA(Compute Unified Device Architecture)以及parallel_for_的支持,这三者都需要运行环境提供底层运行库或者驱动的支持。AMD、Intel、IBM、NVIDIA以及TI的ARM系列芯片都提供了对OpenCL的底层支持的SDK和驱动工具,NVIDIA专门提供了CUDA的底层支持,即CUDA加速只适用于NVIDIA的加速部件[2]。通过代码分析,parallel_for_的底层并行编程支持有TBB、CSTRIPES、OpenMP、GCD、CONCURRENCY。能够使用其中哪种途径实现并行编程,依赖于相应的平台是否提供解决方案,如果移植后的多核DSP平台无并行支持,那么就需要先移植或者实现一个底层多核并行的软件支持。

公摊计价销售模式全国采用情况不一。艾振强介绍,“公摊面积”这个销售概念源自香港,脱胎于香港20世纪50年代“卖楼花(期房)”的售楼模式,2013年起香港转向以套内面积计价的销售模式。

{

通过代码分析,OpenCV函数通过parallel_for_调用,将计算任务再交予OpenMP的#pragma标签实现任务分配,底层实现代码如下所示,上层传递过来的函数最终由pbody执行,而pbody中的数据会被OpenMP的#pragma标签划分到多个核中执行。

OpenCV的parallel_for_底层支持原理:

总之,课程文化在新的远程教育环境下的内涵进一步丰富了。通过远程教育环境下课程文化的建设,使每位学习者能够更新知识结构,还能完善自我学习能力,实现现代教育终身学习的最终目标。

void cv::parallel_for_(const cv::Ranges range,const cv::ParallelLoopBodys body,double nstripes)

{

if(numThreads !=0)

经过多年的研究和尝试,她的兴趣最终转向摄影:尽管商业艺术似乎更青睐斯泰肯(Steichen)、斯蒂格利茨(Stieglitz)或韦斯顿(Weston)等传统大师的作品,她却充满厌倦。她发现了埃德·拉斯查(Ed Ruscha,是一位与波普艺术运动有关的美国艺术家。)的作品,称它是“第一张真正使我感到认同的照片。我热爱这种反审美的特征——灰尘、划痕以及一种看似愚蠢的重复……”

{

ProvyLoopBody pbody(body,range,nstripes);

cv::Range stripeRange=pbody.stripeRange();

int i;

#pragma omp parallel for schedule(dynamic)

for (i=stripeRange.start;i<stripeRange.end;++1)

{

pbody(Range(i,i+1));

}

else

{

(void)nstripes;

body(range);

}

}

基于以上分析,本文提出如下所示的一种OpenCV函数的并行化方法。

  

Figure 4 Process of execution and invocation of OpenCV parallel functions in eight-core case图4 8核情况下OpenCV并行函数执行和调用的过程

OpenCV函数并行改造的一般方法:

Func(in,out,size);//改造前

parallel_for_(Range(0,thread_num),Func_mt(in,out,size));//改造后

struct Func_mt:ParallelLoopBody

{

Func_mt(InputArray_in,OutputArray_out,size_t_size)

{

in=_in;

out=_out;

size=_size;

}

void operator() (const Ranges range) const

{

for(int i=range.start;i++;i<range.end)

Func(in+i*size/range.end,out+i*size/range.end,size/range.end);

}

InputArray in;

OutputArray out;

size_t size;

};

需要改造的功能函数Func需要按照线程数划分计算的起始地址对计算量进行划分,而后封装在ParallelLoopBodyoperator中执行,当调用改造后的parallel_for_函数的时候,函数功能会在底层#para 标签标识的for循环中将pbody函数分配到各个核执行。而pbody函数调用之前封装在operator中划分好的Func功能函数,实现多核并行。

图4描述了8核情况下程序执行和调用的过程。这种改造方法相对于直接使用OpenMP的优势在于遵循了OpenCV原有的代码层次结构,在底层需要改变并行实现方式的时候,无需对上层功能代码进行修改,减少移植到新的嵌入式平台后针对并行支持的修改工作量。

4 结果分析

OpenCV中使用OpenCL实现的函数约200多个[6],通过代码分析,从中选出可以进行缓冲区位置优化以及方便做DMA加速的部分函数,最终处理和改造的函数如表1所示。

对这些函数使用上文中提供的方法进行优化,本文在TI 6678EVM上配置运行频率1 GHz,使用XDS560V2仿真板,在CC S5.5版本,SYS/BIOS 6.35的RTOS操作系统下,编译运行得到的结果如图5和图6所示,获得的加速比如表2所示。

 

Table 1 OpenCV function transformation and experimental calculation scale表1 OpenCV函数改造情况和实验计算规模

  

名称计算规模数据流向优化DMA优化描述binary_op640*480CV_8UC4是是用于所有矩阵二进制处理,与或非异或最大最小arithm_op640*480CV_8UC4是是所有矩阵的加减乘除compare640*480CV_8UC4是否比较两幅图inRange1440*1920CV_8UC1是是检测图像灰度是否在范围内split1440*1920CV_8UC4是否分离成单通道merge1440*1920CV_8UC1*3是否单通道合并成多通道mixChannels1440*1920CV_8UC4是否多通道混合phase640*480CV_32FC4是否求角度cartToPolarpolarToCart640*480CV_32FC4是否笛卡尔和极坐标转换pow640*480CV_32FC4否否求指数Rng:fill960*1280CV_8UC4是否随机数生成

  

Figure 5 Comparison of runtime between six kinds of OpenCV functions图5 六种OpenCV函数改造前后运行时间对比

  

Figure 6 Comparison of runtime between another six kinds of OpenCV functions图6 另外六种 OpenCV函数改造前后运行时间对比

 

Table 2 OpenCV acceleration ratio

 

after the function parallel transformation

 

表2 OpenCV函数并行改造后加速比

  

名称加速比binary_op/bitwise_and3.47arithm_op/multiply5.47compare3.80inRange4.43split7.06merge6.91mixChannels2.55phase7.04cartToPolar4.77polarToCart2.59pow4.80Rng:fill6.29

可以看出,部分数据流向优化和DMA优化能得到比较好的效果,部分效果不明显。这是由于这些函数buf内的计算比较少,Cache加速效果明显,同时在缓冲区内的计算比较少,在缓冲区中耗费的时间少,DMA加速效果不明显,甚至比开Cache的情况差。数据流和DMA优化效果最好的arithm_op单核性能相比没有优化的情况加速达到了3.6倍。多核改造程序执行效率相对于单核优化后的函数加速比在2.55和7.06之间,这可能和具体算法可并行部分的执行时间和不可并行的时间比例有关。

5 结束语

本文实现了OpenCV在TI 6678上的移植,生成了支持绝大多数OpenCV函数的底层静态链接库。同时针对DSP有限的并行支持情况下进行多核优化,结合使用数据流向优化和DMA优化,实现了部分OpenCV函数的并行改造优化,拓展了在单个DSP芯片上的OpenCV多核应用。移植到DSP后,OpenCV在存储搬移上能够进行优化的函数可以进一步挖掘。另外,部分OpenCV的处理功能不需要依赖OpenMP的写直达,以及OpenMP在任务分发的起始、结束和特定的刷新点插入写回等措施进行的Cache一致性维护,可以针对这部分函数的功能特点,使用不依赖OpenMP的底层并行方式进一步提升性能。还可以针对更新版本的OpenCV或者更多型号的多核DSP芯片做相应的移植和多核并行改造。

参考文献:

[1] Kaehler A, Bradski G. Learning OpenCV[M].Sebastop01:O’Reilly Media,Inc,2014.

[2] Gracia I S,Gracia G B,Suarez O D,et al.Learning image processing with OpenCV[M].[S.l.]Packt Open Source,2015.

[3] http://opencv.org.

[4] http://www.ti.com/lsds/ti/processors/technology/libraries/open-cv-libraries.page?keyMatch=openCV&tisearch=Search-EN-Everything.

[5] Coombs J,Prabhu R,Peake G.Overcoming the challenges of porting OpenCV to TI’s embedded ARM+DSP platforms[J].International Journal of Electrical Engineering Education,2012,49(3):260-274.

[6] Stotzer E,Jayaraj A,Ali M,et al.OpenMP on the low-power TI keystone II ARM/DSP system-on-chip[C]∥Proc of International Workshop on OpenMP,2013:114-127.

[7] https://sourceforge.net/projects/emcv.

[8] http://www.cvdsp.wezhan.cn.

[9] Niu Jin-hai. TMS320C66x KeyStone architecture multi-core DSP entry and instance solution[M].Shanghai:Shanghai Jiaotong University Press,2014.(in Chinese)

[10] Su Bao-yu. Research on multi-core DSP image processing system based on TI-C6678 [D].Beijing:Chinese Academy of Sciences University,2014:12-13.(in Chinese)

[11] Johnsson L,Netzer G.The impact of Moore’s law and loss of dennard scaling:Are DSP SoCs an energy efficient alternative to x86 SoCs[J].Journal of Physics:Conference Series,2016,762(1):012022.

[12] Texas Instruments. Multicore programming guide[EB/OL].[2012-11-16].http://www.ti.com,2012.

附中文参考文献:

[9] 牛金海.TMS320C66x KeyStone架构多核DSP入门与实例精解[M].上海:上海交通大学出版社,2014.

[10] 苏保禹.基于 TI-C6678的多核DSP图像处理系统研究[D].北京:中国科学院大学,2014:12-13.

 
李津,罗昕颉,扈啸,陈跃跃
《计算机工程与科学》2018年第05期文献

服务严谨可靠 7×14小时在线支持 支持宝特邀商家 不满意退款

本站非杂志社官网,上千家国家级期刊、省级期刊、北大核心、南大核心、专业的职称论文发表网站。
职称论文发表、杂志论文发表、期刊征稿、期刊投稿,论文发表指导正规机构。是您首选最可靠,最快速的期刊论文发表网站。
免责声明:本网站部分资源、信息来源于网络,完全免费共享,仅供学习和研究使用,版权和著作权归原作者所有
如有不愿意被转载的情况,请通知我们删除已转载的信息 粤ICP备2023046998号