图像融合之拉普拉斯融合(laplacian blending)
一、拉普拉斯融合基本步骤
1. 两幅图像L,R,以及二值掩模mask,给定金字塔层数level。
2. 分别根据L,R构建其对应的拉普拉斯残差金字塔(层数为level),并保留高斯金字塔下采样最顶端的图像(尺寸最小的图像,第level+1层):
拉普拉斯残差金字塔构建方法如下,以L图为例:
(1) 对L进行高斯下采样得到downL,OpenCV中pyrDown()函数可以实现此功能。然后再对downL进行高斯上采样得到upL,OpenCV中pyrUp()函数可以实现此功能。
(2) 计算原图L与upL之间的残差,得到一幅残差图lapL0。作为残差金字塔最低端的图像。
(3) 对downL继续进行(1) (2)操作,不断计算残差图lapL1, lap2, lap3.....lapN。这样得到一系列残差图,即为拉普拉斯残差金字塔。
(4)拉普拉斯 残差金字塔中一共有level幅图像。而我们需要保留第level+1层的高斯下采样图topL,以便后面使用。
3. 二值掩模mask下采样构建高斯金字塔,同样利用pyrDown()实现,共有level+1层。
4. 利用mask金字塔每一层的mask图,将L图和R图的拉普拉斯残差金字塔对应层的图像合并为一幅图像。这样得到合并后的拉普拉斯残差金字塔。同时利用最顶端的mask将步骤2中保留的topL和topR合并为topLR。
5. 以topLR为金字塔最顶端的图像,利用pyrUp()函数对topLR进行高斯上采样,得到upTopLR,并将upTopLR与步骤4中合并后的残差金字塔对应层的图像相加,重建出该层的图像。
6. 重复步骤5,直至重建出第0层,也就是金字塔最低端的图像,即blendImg。输出。
二、代码
拉普拉斯融合的OpenCV实现代码如下:
#include <opencv2/opencv.hpp>
#include <iostream>
#include <string> using namespace std;
using namespace cv; /************************************************************************/
/* 说明:
*金字塔从下到上依次为 [0,1,...,level-1] 层
*blendMask 为图像的掩模
*maskGaussianPyramid为金字塔每一层的掩模
*resultLapPyr 存放每层金字塔中直接用左右两图Laplacian变换拼成的图像
*/
/************************************************************************/ class LaplacianBlending {
private:
Mat left;
Mat right;
Mat blendMask; //Laplacian Pyramids
vector<Mat> leftLapPyr, rightLapPyr, resultLapPyr;
Mat leftHighestLevel, rightHighestLevel, resultHighestLevel;
//mask为三通道方便矩阵相乘
vector<Mat> maskGaussianPyramid; int levels; void buildPyramids()
{
buildLaplacianPyramid(left, leftLapPyr, leftHighestLevel);
buildLaplacianPyramid(right, rightLapPyr, rightHighestLevel);
buildGaussianPyramid();
} void buildGaussianPyramid()
{
//金字塔内容为每一层的掩模
assert(leftLapPyr.size()>); maskGaussianPyramid.clear();
Mat currentImg;
cvtColor(blendMask, currentImg, CV_GRAY2BGR);
//保存mask金字塔的每一层图像
maskGaussianPyramid.push_back(currentImg); //0-level currentImg = blendMask;
for (int l = ; l<levels + ; l++) {
Mat _down;
if (leftLapPyr.size() > l)
pyrDown(currentImg, _down, leftLapPyr[l].size());
else
pyrDown(currentImg, _down, leftHighestLevel.size()); //lowest level Mat down;
cvtColor(_down, down, CV_GRAY2BGR);
//add color blend mask into mask Pyramid
maskGaussianPyramid.push_back(down);
currentImg = _down;
}
} void buildLaplacianPyramid(const Mat& img, vector<Mat>& lapPyr, Mat& HighestLevel)
{
lapPyr.clear();
Mat currentImg = img;
for (int l = ; l<levels; l++) {
Mat down, up;
pyrDown(currentImg, down);
pyrUp(down, up, currentImg.size());
Mat lap = currentImg - up;
lapPyr.push_back(lap);
currentImg = down;
}
currentImg.copyTo(HighestLevel);
} Mat reconstructImgFromLapPyramid()
{
//将左右laplacian图像拼成的resultLapPyr金字塔中每一层
//从上到下插值放大并与残差相加,即得blend图像结果
Mat currentImg = resultHighestLevel;
for (int l = levels - ; l >= ; l--)
{
Mat up;
pyrUp(currentImg, up, resultLapPyr[l].size());
currentImg = up + resultLapPyr[l];
}
return currentImg;
} void blendLapPyrs()
{
//获得每层金字塔中直接用左右两图Laplacian变换拼成的图像resultLapPyr
resultHighestLevel = leftHighestLevel.mul(maskGaussianPyramid.back()) +
rightHighestLevel.mul(Scalar(1.0, 1.0, 1.0) - maskGaussianPyramid.back());
for (int l = ; l<levels; l++)
{
Mat A = leftLapPyr[l].mul(maskGaussianPyramid[l]);
Mat antiMask = Scalar(1.0, 1.0, 1.0) - maskGaussianPyramid[l];
Mat B = rightLapPyr[l].mul(antiMask);
Mat blendedLevel = A + B; resultLapPyr.push_back(blendedLevel);
}
} public:
LaplacianBlending(const Mat& _left, const Mat& _right, const Mat& _blendMask, int _levels) ://construct function, used in LaplacianBlending lb(l,r,m,4);
left(_left), right(_right), blendMask(_blendMask), levels(_levels)
{
assert(_left.size() == _right.size());
assert(_left.size() == _blendMask.size());
//创建拉普拉斯金字塔和高斯金字塔
buildPyramids();
//每层金字塔图像合并为一个
blendLapPyrs();
}; Mat blend()
{
//重建拉普拉斯金字塔
return reconstructImgFromLapPyramid();
}
}; Mat LaplacianBlend(const Mat &left, const Mat &right, const Mat &mask)
{
LaplacianBlending laplaceBlend(left, right, mask, );
return laplaceBlend.blend();
} int main() {
Mat img8UL = imread("data/apple.jpg");
Mat img8UR = imread("data/orange.jpg"); int imgH = img8UL.rows;
int imgW = img8UL.cols; imshow("left", img8UL);
imshow("right", img8UR); Mat img32fL, img32fR;
img8UL.convertTo(img32fL, CV_32F);
img8UR.convertTo(img32fR, CV_32F); //创建mask
Mat mask = Mat::zeros(imgH, imgW, CV_32FC1);
mask(Range::all(), Range(, mask.cols * 0.5)) = 1.0; Mat blendImg = LaplacianBlend(img32fL, img32fR, mask); blendImg.convertTo(blendImg, CV_8UC3);
imshow("blended", blendImg); waitKey();
return ;
}
融合结果如下图:

金字塔层数level=5 金字塔层数level=10

附上自己实现pyrDown和pyrUp写的拉普拉斯融合,仅供参考:
#include <opencv2\opencv.hpp>
#include <iostream>
#include <string> using namespace std; //#define DEBUG void borderInterp(cv::Mat &_src, int radius)
{
int imgH = _src.rows;
int imgW = _src.cols;
float *pSrc = (float*)_src.data;
for (int i = radius; i < imgH-radius*; i++)
{
for (int j = ; j < ; j++)
{
int srcIdx = (i*imgW + j + ) * ;
int dstIdx = (i*imgW + j) * ;
pSrc[dstIdx] = pSrc[srcIdx];
pSrc[dstIdx + ] = pSrc[srcIdx + ];
pSrc[dstIdx + ] = pSrc[srcIdx + ];
}
for (int j = imgW - radius; j < imgW; j++)
{
int srcIdx = (i*imgW + j - ) * ;
int dstIdx = (i*imgW + j) * ;
pSrc[dstIdx] = pSrc[srcIdx];
pSrc[dstIdx + ] = pSrc[srcIdx + ];
pSrc[dstIdx + ] = pSrc[srcIdx + ]; }
}
for (int j = ; j < imgW; j++)
{
for (int i = ; i < ; i++)
{
int srcIdx = ((i + )*imgW + j) * ;
int dstIdx = (i*imgW + j) * ;
pSrc[dstIdx] = pSrc[srcIdx];
pSrc[dstIdx + ] = pSrc[srcIdx + ];
pSrc[dstIdx + ] = pSrc[srcIdx + ];
}
for (int i = imgH - radius; i < imgH; i++)
{
int srcIdx = ((i - )*imgW + j) * ;
int dstIdx = (i*imgW + j) * ;
pSrc[dstIdx] = pSrc[srcIdx];
pSrc[dstIdx + ] = pSrc[srcIdx + ];
pSrc[dstIdx + ] = pSrc[srcIdx + ];
}
}
} void myPyrDown(cv::Mat src, cv::Mat &dst, cv::Size dSize)
{
dSize = dSize.area() == ? cv::Size((src.cols + ) / , (src.rows + ) / ) : dSize; float scale = . / ; int imgH = src.rows;
int imgW = src.cols;
cv::Mat _src = cv::Mat::zeros(imgH + , imgW + , CV_32FC3);
int _imgH = _src.rows;
int _imgW = _src.cols;
src.copyTo(_src(cv::Rect(, , imgW, imgH)));
borderInterp(_src, ); //高斯卷积
cv::Mat gaussImg = cv::Mat::zeros(imgH, imgW, CV_32FC3);
cv::Mat tmpRowGaussImg = _src.clone();
float *pSrc = (float*)_src.data;
float *pRowGaussImg = (float*)tmpRowGaussImg.data;
//行卷积
for (int i = ; i < imgH+; i++)
{
for (int j = ; j < imgW+; j++)
{
float val[] = { };
int idx = i*_imgW + j;
for (int chan = ; chan < ; chan++)
{
val[chan] += pSrc[(idx - ) * + chan] + pSrc[(idx + ) * + chan]
+ * (pSrc[(idx - ) * + chan] + pSrc[(idx + ) * + chan])
+ * pSrc[idx * + chan];
}
pRowGaussImg[idx * ] = val[] * scale;
pRowGaussImg[idx * + ] = val[] * scale;
pRowGaussImg[idx * + ] = val[] * scale;
}
} float *pGaussImg = (float*)gaussImg.data;
//列卷积
for (int j = ; j < imgW; j++)
{
for (int i = ; i < imgH; i++)
{
int gi = i + ;
int gj = j + ;
float val[] = { };
int idx = gi*_imgW + gj;
for (int chan = ; chan < ; chan++)
{
val[chan] += pRowGaussImg[(idx-*_imgW) * + chan] + pRowGaussImg[(idx + *_imgW) * + chan]
+ * (pRowGaussImg[(idx - _imgW) * + chan] + pRowGaussImg[(idx + _imgW) * + chan])
+ * pRowGaussImg[idx * + chan];
} int id = (i*imgW + j) * ;
pGaussImg[id] = val[] * scale;
pGaussImg[id + ] = val[] * scale;
pGaussImg[id + ] = val[] * scale;
}
} int downH = dSize.height;
int downW = dSize.width; if (abs(downH * - imgH) > ) downH = imgH*0.5;
if (abs(downW * - imgW) > ) downW = imgW*0.5;
downH = (downH < ) ? : downH;
downW = (downW < ) ? : downW; dst = cv::Mat::zeros(downH, downW, CV_32FC3);
float *pDst = (float*)dst.data;
for (int i = ; i < imgH; i++)
{
for (int j = ; j < imgW; j++)
{
if (i % != || j % != ) continue;
int srcIdx = (i*imgW + j) * ;
int y = int((i+) * 0.5);
int x = int((j+) * 0.5);
y = (y >= downH) ? (downH - ) : y;
x = (x >= downW) ? (downW - ) : x;
int dstIdx = (y*downW + x) * ;
pDst[dstIdx] = pGaussImg[srcIdx];
pDst[dstIdx + ] = pGaussImg[srcIdx + ];
pDst[dstIdx + ] = pGaussImg[srcIdx + ];
}
}
} void myPyrUp(cv::Mat src, cv::Mat &dst, cv::Size dSize)
{
dSize = dSize.area() == ? cv::Size(src.cols * , src.rows * ) : dSize;
cv::Mat _src;
src.convertTo(_src, CV_32FC3); float scale = . / ; int imgH = src.rows;
int imgW = src.cols;
int upImgH = dSize.height;
int upImgW = dSize.width; if (abs(upImgH - imgH * ) > upImgH % ) upImgH = imgH*;
if (abs(upImgW - imgW * ) > upImgW % ) upImgW = imgW*; cv::Mat upImg = cv::Mat::zeros(upImgH, upImgW, CV_32FC3);
float *pSrc = (float*)_src.data;
float *pUpImg = (float*)upImg.data;
for (int i = ; i < upImgH; i++)
{
for (int j = ; j < upImgW; j++)
{
if (i % != || j % != ) continue;
int dstIdx = (i*upImgW + j)*;
int y = int((i+)*0.5);
int x = int((j+)*0.5);
y = (y >= imgH) ? (imgH - ) : y;
x = (x >= imgW) ? (imgW - ) : x;
int srcIdx = (y*imgW + x) * ; pUpImg[dstIdx] = pSrc[srcIdx];
pUpImg[dstIdx + ] = pSrc[srcIdx + ];
pUpImg[dstIdx + ] = pSrc[srcIdx + ];
}
} dst = cv::Mat::zeros(dSize, CV_32FC3);
cv::Mat _upImg = cv::Mat::zeros(upImgH + , upImgW + , CV_32FC3);
int _imgH = _upImg.rows;
int _imgW = _upImg.cols;
upImg.copyTo(_upImg(cv::Rect(, , upImgW, upImgH)));
borderInterp(_upImg, ); //高斯卷积
cv::Mat tempRowGaussImg = _upImg.clone();
float *pUpData = (float*)_upImg.data;
float *pRowGaussImg = (float*)tempRowGaussImg.data;
//行卷积
for (int i = ; i < upImgH + ; i++)
{
for (int j = ; j < upImgW + ; j++)
{
float val[] = { };
int idx = i*_imgW + j;
for (int chan = ; chan < ; chan++)
{
val[chan] += pUpData[(idx - ) * + chan] + pUpData[(idx + ) * + chan]
+ * (pUpData[(idx - ) * + chan] + pUpData[(idx + ) * + chan])
+ * pUpData[idx * + chan];
} pRowGaussImg[idx * ] = val[] * scale;
pRowGaussImg[idx * + ] = val[] * scale;
pRowGaussImg[idx * + ] = val[] * scale;
}
} //列卷积
float *pDst = (float*)dst.data;
for (int j = ; j < upImgW; j++)
{
for (int i = ; i < upImgH; i++)
{
int gi = i + ;
int gj = j + ;
float val[] = { };
int idx = gi*_imgW + gj;
for (int chan = ; chan < ; chan++)
{
val[chan] += pRowGaussImg[(idx - * _imgW) * + chan] + pRowGaussImg[(idx + * _imgW) * + chan]
+ * (pRowGaussImg[(idx - _imgW) * + chan] + pRowGaussImg[(idx + _imgW) * + chan])
+ * pRowGaussImg[idx * + chan];
} int id = (i*upImgW + j) * ;
pDst[id] = val[] * scale;
pDst[id + ] = val[] * scale;
pDst[id + ] = val[] * scale;
}
}
} void buildLaplacianPyramid(cv::Mat srcImg, vector<cv::Mat> &pyramidImgs, cv::Mat &topLevelImg, int levels)
{
cv::Mat currentImg = srcImg;
for (int k = ; k < levels; k++)
{
cv::Mat downImg, upImg, lpImg; #ifdef DEBUG
cv::pyrDown(currentImg, downImg);
cv::pyrUp(downImg, upImg, currentImg.size());
#else
myPyrDown(currentImg, downImg, cv::Size());
myPyrUp(downImg, upImg, currentImg.size());
#endif lpImg = currentImg - upImg;
pyramidImgs.push_back(lpImg);
currentImg = downImg;
}
currentImg.copyTo(topLevelImg);
} void buildGaussPyramid(cv::Mat mask, vector<cv::Mat> &maskGaussPyramidImgs, vector<cv::Mat> pyramidImgs,cv::Mat topLevelImg, int levels)
{
cv::Mat currentMask;
//mask转3通道
if (mask.channels() == )
{
cv::cvtColor(mask, currentMask, CV_GRAY2BGR);
}
else if(mask.channels()==)
{
currentMask = mask;
} maskGaussPyramidImgs.push_back(currentMask);
for (int k = ; k < levels+; k++)
{
cv::Mat downMask;
if (k < levels)
{
#ifdef DEBUG
cv::pyrDown(currentMask, downMask, pyramidImgs[k].size());
#else
myPyrDown(currentMask, downMask, pyramidImgs[k].size());
#endif
}
else
{
#ifdef DEBUG
cv::pyrDown(currentMask, downMask, topLevelImg.size());
#else
myPyrDown(currentMask, downMask, topLevelImg.size());
#endif
} maskGaussPyramidImgs.push_back(downMask);
currentMask = downMask;
}
} void buildResultPyramid(vector<cv::Mat> leftPyramidImgs, vector<cv::Mat> rightPyramidImgs, vector<cv::Mat> maskPyramids, vector<cv::Mat> &resultPyramidImgs, int levels)
{ for (int k = ; k < levels; k++)
{
cv::Mat left = leftPyramidImgs[k].mul(maskPyramids[k]);
cv::Mat right = rightPyramidImgs[k].mul(cv::Scalar(1.0,1.0,1.0) - maskPyramids[k]);
cv::Mat result = left + right;
resultPyramidImgs.push_back(result);
} } void reconstruct(vector<cv::Mat> lpPyramidImgs, cv::Mat blendTopLevelImg, cv::Mat &blendImg, int levels)
{
cv::Mat currentImg = blendTopLevelImg;
for (int k = levels - ; k >= ; k--)
{
cv::Mat upImg;
#ifdef DEBUG
cv::pyrUp(currentImg, upImg, lpPyramidImgs[k].size());
#else
myPyrUp(currentImg, upImg, lpPyramidImgs[k].size());
#endif
currentImg = upImg + lpPyramidImgs[k];
}
currentImg.copyTo(blendImg);
} cv::Mat laplacianBlending(cv::Mat leftImg, cv::Mat rightImg, cv::Mat mask)
{
cv::Mat leftImg32f, rightImg32f, mask32f;
leftImg.convertTo(leftImg32f, CV_32FC1);
rightImg.convertTo(rightImg32f, CV_32FC1);
mask.convertTo(mask32f, CV_32FC1); vector<cv::Mat> leftLpPyramidImgs, rightLpPyramidImgs, resultLpPyramidImgs, gaussPyramidMaskImgs;
cv::Mat leftTopLevelImg, rightTopLevelImg;
int levels =;
//拉普拉斯金字塔
buildLaplacianPyramid(leftImg32f, leftLpPyramidImgs, leftTopLevelImg, levels);
buildLaplacianPyramid(rightImg32f, rightLpPyramidImgs, rightTopLevelImg, levels);
//mask创建gauss金字塔
buildGaussPyramid(mask32f, gaussPyramidMaskImgs, leftLpPyramidImgs, leftTopLevelImg, levels);
//结合左右两图的laplacian残差图
buildResultPyramid(leftLpPyramidImgs, rightLpPyramidImgs, gaussPyramidMaskImgs, resultLpPyramidImgs, levels);
//
cv::Mat blendImg = cv::Mat::zeros(leftImg.size(), CV_32FC3); cv::Mat blendTopLevelImg = leftTopLevelImg.mul(gaussPyramidMaskImgs[levels]) + rightTopLevelImg.mul(cv::Scalar(1.0, 1.0, 1.0) - gaussPyramidMaskImgs[levels]);
reconstruct(resultLpPyramidImgs, blendTopLevelImg, blendImg, levels); blendImg.convertTo(blendImg, CV_8UC3);
return blendImg;
} void main()
{
cv::Mat appleImg = cv::imread("data/apple.jpg");
cv::Mat pearImg = cv::imread("data/orange.jpg"); int imgH = appleImg.rows;
int imgW = appleImg.cols;
cv::Mat mask = cv::Mat::zeros(imgH, imgW, CV_32FC1);
mask(cv::Range::all(), cv::Range(, imgW*0.5)) = 1.0;
cv::Mat blendImg = laplacianBlending(appleImg, pearImg, mask);
cv::namedWindow("blendImg", );
cv::imshow("blendImg", blendImg);
cv::imwrite("data/blendImg.png", blendImg);
cv::waitKey();
}
图像融合之拉普拉斯融合(laplacian blending)的更多相关文章
- 图像融合之泊松融合(Possion Matting)
前面有介绍拉普拉斯融合,今天说下OpenCV泊松融合使用.顺便提一下,泊松是拉普拉斯的学生. 泊松融合的原理请参考这篇博文https://blog.csdn.net/u011534057/articl ...
- 拉普拉斯矩阵(Laplacian Matrix) 及半正定性证明
摘自 https://blog.csdn.net/beiyangdashu/article/details/49300479 和 https://en.wikipedia.org/wiki/Lapla ...
- 图像sift配准后融合
image rectification 图像校正 在配准时,先找到特征点,找到特征点后剔除伪匹配点. 然后针对两幅图像做几何矫正(一般通过估计出来的仿射矩阵完成). 这部完成后,图像可以匹配了,但是两 ...
- SC3聚类 | 拉普拉斯矩阵 | Laplacian matrix | 图论 | R代码
Laplacian和PCA貌似是同一种性质的方法,坐标系变换.只是拉普拉斯属于图论的范畴,术语更加专业了. 要看就把一篇文章看完整,再看其中有什么值得借鉴的,总结归纳理解后的东西才是属于你的. 问题: ...
- 利用OpenCV实现图像拼接Stitching模块讲解
https://zhuanlan.zhihu.com/p/71777362 1.1 图像拼接基本步骤 图像拼接的完整流程如上所示,首先对输入图像提取鲁棒的特征点,并根据特征描述子完成特征点的匹配,然后 ...
- SSE图像算法优化系列二十九:基础的拉普拉斯金字塔融合用于改善图像增强中易出现的过增强问题(一)
拉普拉斯金字塔融合是多图融合相关算法里最简单和最容易实现的一种,我们在看网络上大部分的文章都是在拿那个苹果和橙子融合在一起,变成一个果橙的效果作为例子说明.在这方面确实融合的比较好.但是本文我们主要讲 ...
- 基于均值坐标(Mean-Value Coordinates)的图像融合算法的具体实现
目录 1. 概述 2. 实现 2.1. 准备 2.2. 核心 2.2.1. 均值坐标(Mean-Value Coordinates) 2.2.2. ROI边界栅格化 2.2.3. 核心实现 2.2.4 ...
- 基于均值坐标(Mean-Value Coordinates)的图像融合算法的优化实现
目录 1. 概述 2. 实现 2.1. 原理 2.2. 核心代码 2.3. 第二种优化 3. 结果 1. 概述 我在之前的文章<基于均值坐标(Mean-Value Coordinates)的图像 ...
- DirectX基础学习系列5 融合技术
7.1融合方程 1概念 融合技术将当前光栅化像素的颜色与以前已光栅化并处于同一个位置的像素颜色进行合成,即将当前要进行光栅化的三角形单元与已写入后台的像素进行融合 2需要遵循的原则: (1)先绘制不需 ...
随机推荐
- python 内置函数之lambda-filter-reduce-apply-map
(1)lambda lambda是Python中一个很有用的语法,它允许你快速定义单行最小函数.类似于C语言中的宏,可以用在任何需要函数的地方. 基本语法如下: 函数名 = lambda args1, ...
- HashMap 的底层原理
1. HashMap的数据结构 数据结构中有数组和链表来实现对数据的存储,但这两者基本上是两个极端. 数组 数组存储区间是连续的,占用内存严重,故空间复杂的很大.但数组的二分查找时间复杂度小,为O(1 ...
- 其他—cooki和session
cookie Cookie的由来 大家都知道HTTP协议是无状态的. 无状态的意思是每次请求都是独立的,它的执行情况和结果与前面的请求和之后的请求都无直接关系,它不会受前面的请求响应情况直接影响,也不 ...
- Centos7.x:开机启动服务的配置和管理
一.开机启动服务的配置 1.创建服务配置(权限754) vim /usr/lib/systemd/system/nginx.service 文件内容解释 [Unit]:服务的说明Description ...
- GIT入门笔记(9)- git的add和commit机制原理
工作区有一个隐藏目录.git,这个不算工作区,而是Git的版本库. Git的版本库里存了很多东西,其中最重要的就是称为stage(或者叫index)的暂存区,还有Git为我们自动创建的第一个分支mas ...
- Django REST framework+Vue 打造生鲜超市(四)
五.商品列表页 5.1.django的view实现商品列表页 (1)goods/view_base.py 在goods文件夹下面新建view_base.py,为了区分django和django res ...
- mybatis的generator中xml配置问题
<!-- 生成模型的包名和位置 --> <javaModelGenerator targetPackage="com.sung.risk.model.biz" t ...
- shell:正则表达式和文本处理器
1.什么是正则 正则就是用一些具有特殊含义的符号组合到一起(称为正则表达式)来描述字符或者字符串的方法.或者说:正则就是用来描述一类事物的规则. 生活中处处都是正则: 比如我们描述:4条腿 你可能会想 ...
- 前端 jQuery
一.jQuery是什么? <1>jQuery由美国人John Resig创建,至今已吸引了来自世界各地众多JavaScript高手加入其team. <2>jQuery是继pro ...
- 编写CGI程序步骤
CGI common gateway interface 可以让一个客户端,从网页浏览器向服务器请求数据, 这是描述客户端和服务器程序之间传输数据的一种标准. CGI是运行在服务器上的程序,提供同客户 ...