/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// Intel License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000, Intel Corporation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of Intel Corporation may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "_cv.h" #define _CV_SNAKE_BIG 2.e+38f
#define _CV_SNAKE_IMAGE 1
#define _CV_SNAKE_GRAD 2 /*F///////////////////////////////////////////////////////////////////////////////////////
// Name: icvSnake8uC1R
// Purpose:
// Context:
// Parameters:
// src - source image,
// srcStep - its step in bytes,
// roi - size of ROI,
// pt - pointer to snake points array
// n - size of points array,
// alpha - pointer to coefficient of continuity energy,
// beta - pointer to coefficient of curvature energy,
// gamma - pointer to coefficient of image energy,
// coeffUsage - if CV_VALUE - alpha, beta, gamma point to single value
// if CV_MATAY - point to arrays
// criteria - termination criteria.
// scheme - image energy scheme
// if _CV_SNAKE_IMAGE - image intensity is energy
// if _CV_SNAKE_GRAD - magnitude of gradient is energy
// Returns:
//F*/ static CvStatus
icvSnake8uC1R( unsigned char *src, //原始图像数据
int srcStep, //每行的字节数
CvSize roi, //图像尺寸
CvPoint * pt, //轮廓点(变形对象)
int n, //轮廓点的个数
float *alpha, //指向α的指针,α能够是单个值,也能够是与轮廓点个数一致的数组
float *beta, //β的值,同α
float *gamma, //γ的值,同α
int coeffUsage, //确定αβγ是用作单个值还是个数组
CvSize win, //每一个点用于搜索的最小的领域大小,宽度为奇数
CvTermCriteria criteria, //递归迭代终止的条件准则
int scheme ) //确定图像能量场的数据选择,1为灰度,2为灰度梯度
{
int i, j, k;
int neighbors = win.height * win.width; //当前点领域中点的个数 //当前点的位置
int centerx = win.width >> 1;
int centery = win.height >> 1; float invn; //n 的倒数?
int iteration = 0; //迭代次数
int converged = 0; //收敛标志,0为非收敛 //能量
float *Econt; //
float *Ecurv; //轮廓曲线能量
float *Eimg; //图像能量
float *E; // //αβγ的副本
float _alpha, _beta, _gamma; /*#ifdef GRAD_SNAKE */
float *gradient = NULL;
uchar *map = NULL;
int map_width = ((roi.width - 1) >> 3) + 1;
int map_height = ((roi.height - 1) >> 3) + 1;
CvSepFilter pX, pY;
#define WTILE_SIZE 8
#define TILE_SIZE (WTILE_SIZE + 2)
short dx[TILE_SIZE*TILE_SIZE], dy[TILE_SIZE*TILE_SIZE];
CvMat _dx = cvMat( TILE_SIZE, TILE_SIZE, CV_16SC1, dx );
CvMat _dy = cvMat( TILE_SIZE, TILE_SIZE, CV_16SC1, dy );
CvMat _src = cvMat( roi.height, roi.width, CV_8UC1, src ); /* inner buffer of convolution process */
//char ConvBuffer[400]; /*#endif */ //检点參数的合理性
/* check bad arguments */
if( src == NULL )
return CV_NULLPTR_ERR;
if( (roi.height <= 0) || (roi.width <= 0) )
return CV_BADSIZE_ERR;
if( srcStep < roi.width )
return CV_BADSIZE_ERR;
if( pt == NULL )
return CV_NULLPTR_ERR;
if( n < 3 ) //轮廓点至少要三个
return CV_BADSIZE_ERR;
if( alpha == NULL )
return CV_NULLPTR_ERR;
if( beta == NULL )
return CV_NULLPTR_ERR;
if( gamma == NULL )
return CV_NULLPTR_ERR;
if( coeffUsage != CV_VALUE && coeffUsage != CV_ARRAY )
return CV_BADFLAG_ERR;
if( (win.height <= 0) || (!(win.height & 1))) //邻域搜索窗体得是奇数
return CV_BADSIZE_ERR;
if( (win.width <= 0) || (!(win.width & 1)))
return CV_BADSIZE_ERR; invn = 1 / ((float) n); //轮廓点数n的倒数,用于求平均? if( scheme == _CV_SNAKE_GRAD )
{
//X方向上和Y方向上的Scoble梯度算子,用于求图像的梯度,
//处理的图像最大尺寸为TILE_SIZE+2,此例为12,算子半长为3即{-3,-2,-1,0,1,2,3}
//处理后的数据类型为16位符号数,分别存放在_dx,_dy矩阵中,长度为10
pX.init_deriv( TILE_SIZE+2, CV_8UC1, CV_16SC1, 1, 0, 3 );
pY.init_deriv( TILE_SIZE+2, CV_8UC1, CV_16SC1, 0, 1, 3 );
//图像梯度存放缓冲区
gradient = (float *) cvAlloc( roi.height * roi.width * sizeof( float )); if( !gradient )
return CV_OUTOFMEM_ERR;
//map用于标志对应位置的分块的图像能量是否已经求得
map = (uchar *) cvAlloc( map_width * map_height );
if( !map )
{
cvFree( &gradient );
return CV_OUTOFMEM_ERR;
}
/* clear map - no gradient computed */
//清除map标志
memset( (void *) map, 0, map_width * map_height );
}
//各种能量的存放处,取每点的邻域的能量
Econt = (float *) cvAlloc( neighbors * sizeof( float ));
Ecurv = (float *) cvAlloc( neighbors * sizeof( float ));
Eimg = (float *) cvAlloc( neighbors * sizeof( float ));
E = (float *) cvAlloc( neighbors * sizeof( float ));
//開始迭代
while( !converged ) //收敛标志无效时进行
{
float ave_d = 0; //轮廓各点的平均距离
int moved = 0; //轮廓变形时,发生移动的数量 converged = 0; //标志未收敛
iteration++; //更新迭代次数+1 //计算轮廓中各点的平均距离
/* compute average distance */
//从点0到点n-1的距离和
for( i = 1; i < n; i++ )
{
int diffx = pt[i - 1].x - pt[i].x;
int diffy = pt[i - 1].y - pt[i].y; ave_d += cvSqrt( (float) (diffx * diffx + diffy * diffy) );
}
//再加上从点n-1到点0的距离,形成回路轮廓
ave_d += cvSqrt( (float) ((pt[0].x - pt[n - 1].x) *
(pt[0].x - pt[n - 1].x) +
(pt[0].y - pt[n - 1].y) * (pt[0].y - pt[n - 1].y)));
//求平均,得出平均距离
ave_d *= invn;
/* average distance computed */ //对于每一个轮廓点进行特定循环迭代求解
for( i = 0; i < n; i++ )
{
/* Calculate Econt */
//初始化各个能量
float maxEcont = 0;
float maxEcurv = 0;
float maxEimg = 0;
float minEcont = _CV_SNAKE_BIG;
float minEcurv = _CV_SNAKE_BIG;
float minEimg = _CV_SNAKE_BIG;
float Emin = _CV_SNAKE_BIG;
//初始化变形后轮廓点的偏移量
int offsetx = 0;
int offsety = 0;
float tmp; //计算边界
/* compute bounds */
//计算合理的搜索边界,以防领域搜索超过ROI图像的范围
int left = MIN( pt[i].x, win.width >> 1 );
int right = MIN( roi.width - 1 - pt[i].x, win.width >> 1 );
int upper = MIN( pt[i].y, win.height >> 1 );
int bottom = MIN( roi.height - 1 - pt[i].y, win.height >> 1 );
//初始化Econt
maxEcont = 0;
minEcont = _CV_SNAKE_BIG;
//在合理的搜索范围内进行Econt的计算
for( j = -upper; j <= bottom; j++ )
{
for( k = -left; k <= right; k++ )
{
int diffx, diffy;
float energy;
//在轮廓点集的首尾相接处作对应处理,求轮廓点差分
if( i == 0 )
{
diffx = pt[n - 1].x - (pt[i].x + k);
diffy = pt[n - 1].y - (pt[i].y + j);
}
else
//在其它地方作一般处理 {
diffx = pt[i - 1].x - (pt[i].x + k);
diffy = pt[i - 1].y - (pt[i].y + j);
}
//将邻域陈列坐标转成Econt数组的下标序号,计算邻域中每点的Econt
//Econt的值等于平均距离和此点和上一点的距离的差的绝对值(这是怎么来的?)
Econt[(j + centery) * win.width + k + centerx] = energy =
(float) fabs( ave_d -
cvSqrt( (float) (diffx * diffx + diffy * diffy) ));
//求出全部邻域点中的Econt的最大值和最小值
maxEcont = MAX( maxEcont, energy );
minEcont = MIN( minEcont, energy );
}
}
//求出邻域点中最大值和最小值之差,并对全部的邻域点的Econt进行标准归一化,若最大值最小
//相等,则邻域中的点Econt全相等,Econt归一化束缚为0
tmp = maxEcont - minEcont;
tmp = (tmp == 0) ? 0 : (1 / tmp);
for( k = 0; k < neighbors; k++ )
{
Econt[k] = (Econt[k] - minEcont) * tmp;
} //计算每点的Ecurv
/* Calculate Ecurv */
maxEcurv = 0;
minEcurv = _CV_SNAKE_BIG;
for( j = -upper; j <= bottom; j++ )
{
for( k = -left; k <= right; k++ )
{
int tx, ty;
float energy;
//第一个点的二阶差分
if( i == 0 )
{
tx = pt[n - 1].x - 2 * (pt[i].x + k) + pt[i + 1].x;
ty = pt[n - 1].y - 2 * (pt[i].y + j) + pt[i + 1].y;
}
//最后一个点的二阶差分
else if( i == n - 1 )
{
tx = pt[i - 1].x - 2 * (pt[i].x + k) + pt[0].x;
ty = pt[i - 1].y - 2 * (pt[i].y + j) + pt[0].y;
}
//其余点的二阶差分
else
{
tx = pt[i - 1].x - 2 * (pt[i].x + k) + pt[i + 1].x;
ty = pt[i - 1].y - 2 * (pt[i].y + j) + pt[i + 1].y;
}
//转换坐标为数组序号,并求各点的Ecurv的值,二阶差分后取平方
Ecurv[(j + centery) * win.width + k + centerx] = energy =
(float) (tx * tx + ty * ty);
//取最小的Ecurv和最大的Ecurv
maxEcurv = MAX( maxEcurv, energy );
minEcurv = MIN( minEcurv, energy );
}
}
//对Ecurv进行标准归一化
tmp = maxEcurv - minEcurv;
tmp = (tmp == 0) ? 0 : (1 / tmp);
for( k = 0; k < neighbors; k++ )
{
Ecurv[k] = (Ecurv[k] - minEcurv) * tmp;
} //求Eimg
/* Calculate Eimg */
for( j = -upper; j <= bottom; j++ )
{
for( k = -left; k <= right; k++ )
{
float energy;
//若採用灰度梯度数据
if( scheme == _CV_SNAKE_GRAD )
{
/* look at map and check status */
int x = (pt[i].x + k)/WTILE_SIZE;
int y = (pt[i].y + j)/WTILE_SIZE;
//若此处的图像能量还没有获取,则对此处对应的图像分块进行图像能量的求解
if( map[y * map_width + x] == 0 )
{
int l, m; /* evaluate block location */
//计算要进行梯度算子处理的图像块的位置
int upshift = y ? 1 : 0;
int leftshift = x ? 1 : 0;
int bottomshift = MIN( 1, roi.height - (y + 1)*WTILE_SIZE );
int rightshift = MIN( 1, roi.width - (x + 1)*WTILE_SIZE );
//图像块的位置大小(因为原ROI不一定是8的倍数,所以图像块会大小不一)
CvRect g_roi = { x*WTILE_SIZE - leftshift, y*WTILE_SIZE - upshift,
leftshift + WTILE_SIZE + rightshift, upshift + WTILE_SIZE + bottomshift };
CvMat _src1;
cvGetSubArr( &_src, &_src1, g_roi ); //得到图像块的数据
//分别对图像的X方向和Y方向进行梯度算子
pX.process( &_src1, &_dx );
pY.process( &_src1, &_dy );
//求分块区域中的每一个点的梯度
for( l = 0; l < WTILE_SIZE + bottomshift; l++ )
{
for( m = 0; m < WTILE_SIZE + rightshift; m++ )
{
gradient[(y*WTILE_SIZE + l) * roi.width + x*WTILE_SIZE + m] =
(float) (dx[(l + upshift) * TILE_SIZE + m + leftshift] *
dx[(l + upshift) * TILE_SIZE + m + leftshift] +
dy[(l + upshift) * TILE_SIZE + m + leftshift] *
dy[(l + upshift) * TILE_SIZE + m + leftshift]);
}
}
//map对应位置置1表示此处图像能量已经获取
map[y * map_width + x] = 1;
}
//以梯度数据作为图像能量
Eimg[(j + centery) * win.width + k + centerx] = energy =
gradient[(pt[i].y + j) * roi.width + pt[i].x + k];
}
else
{
//以灰度作为图像能量
Eimg[(j + centery) * win.width + k + centerx] = energy =
src[(pt[i].y + j) * srcStep + pt[i].x + k];
}
//获得邻域中最大和最小的图像能量
maxEimg = MAX( maxEimg, energy );
minEimg = MIN( minEimg, energy );
}
}
//Eimg的标准归一化
tmp = (maxEimg - minEimg);
tmp = (tmp == 0) ? 0 : (1 / tmp); for( k = 0; k < neighbors; k++ )
{
Eimg[k] = (minEimg - Eimg[k]) * tmp;
}
//增加系数
/* locate coefficients */
if( coeffUsage == CV_VALUE)
{
_alpha = *alpha;
_beta = *beta;
_gamma = *gamma;
}
else
{
_alpha = alpha[i];
_beta = beta[i];
_gamma = gamma[i];
} /* Find Minimize point in the neighbors */
//求得每一个邻域点的Snake能量
for( k = 0; k < neighbors; k++ )
{
E[k] = _alpha * Econt[k] + _beta * Ecurv[k] + _gamma * Eimg[k];
}
Emin = _CV_SNAKE_BIG;
//获取最小的能量,以及对应的邻域中的相对位置
for( j = -upper; j <= bottom; j++ )
{
for( k = -left; k <= right; k++ )
{ if( E[(j + centery) * win.width + k + centerx] < Emin )
{
Emin = E[(j + centery) * win.width + k + centerx];
offsetx = k;
offsety = j;
}
}
}
//假设轮廓点发生改变,则记得移动次数
if( offsetx || offsety )
{
pt[i].x += offsetx;
pt[i].y += offsety;
moved++;
}
} //各个轮廓点迭代计算完毕后,假设没有移动的点了,则收敛标志位有效,停止迭代
converged = (moved == 0);
//达到最大迭代次数时,收敛标志位有效,停止迭代
if( (criteria.type & CV_TERMCRIT_ITER) && (iteration >= criteria.max_iter) )
converged = 1;
//到大对应精度时,停止迭代(与第一个条件有同样效果)
if( (criteria.type & CV_TERMCRIT_EPS) && (moved <= criteria.epsilon) )
converged = 1;
} //释放各个缓冲区
cvFree( &Econt );
cvFree( &Ecurv );
cvFree( &Eimg );
cvFree( &E ); if( scheme == _CV_SNAKE_GRAD )
{
cvFree( &gradient );
cvFree( &map );
}
return CV_OK;
} CV_IMPL void
cvSnakeImage( const IplImage* src, CvPoint* points,
int length, float *alpha,
float *beta, float *gamma,
int coeffUsage, CvSize win,
CvTermCriteria criteria, int calcGradient )
{ CV_FUNCNAME( "cvSnakeImage" ); __BEGIN__; uchar *data;
CvSize size;
int step; if( src->nChannels != 1 )
CV_ERROR( CV_BadNumChannels, "input image has more than one channel" ); if( src->depth != IPL_DEPTH_8U )
CV_ERROR( CV_BadDepth, cvUnsupportedFormat ); cvGetRawData( src, &data, &step, &size ); IPPI_CALL( icvSnake8uC1R( data, step, size, points, length,
alpha, beta, gamma, coeffUsage, win, criteria,
calcGradient ? _CV_SNAKE_GRAD : _CV_SNAKE_IMAGE ));
__END__;
} /* end of file */ 測试应用程序 #include "stdafx.h"
#include <iostream>
#include <string.h>
#include <cxcore.h>
#include <cv.h>
#include <highgui.h>
#include <fstream> IplImage *image = 0 ; //原始图像
IplImage *image2 = 0 ; //原始图像copy using namespace std;
int Thresholdness = 141;
int ialpha = 20;
int ibeta=20;
int igamma=20; void onChange(int pos)
{ if(image2) cvReleaseImage(&image2);
if(image) cvReleaseImage(&image); image2 = cvLoadImage("grey.bmp",1); //显示图片
image= cvLoadImage("grey.bmp",0); cvThreshold(image,image,Thresholdness,255,CV_THRESH_BINARY); //切割域值 CvMemStorage* storage = cvCreateMemStorage(0);
CvSeq* contours = 0; cvFindContours( image, storage, &contours, sizeof(CvContour), //寻找初始化轮廓
CV_RETR_EXTERNAL , CV_CHAIN_APPROX_SIMPLE ); if(!contours) return ;
int length = contours->total;
if(length<10) return ;
CvPoint* point = new CvPoint[length]; //分配轮廓点 CvSeqReader reader;
CvPoint pt= cvPoint(0,0);;
CvSeq *contour2=contours; cvStartReadSeq(contour2, &reader);
for (int i = 0; i < length; i++)
{
CV_READ_SEQ_ELEM(pt, reader);
point[i]=pt;
}
cvReleaseMemStorage(&storage); //显示轮廓曲线
for(int i=0;i<length;i++)
{
int j = (i+1)%length;
cvLine( image2, point[i],point[j],CV_RGB( 0, 0, 255 ),1,8,0 );
} float alpha=ialpha/100.0f;
float beta=ibeta/100.0f;
float gamma=igamma/100.0f; CvSize size;
size.width=3;
size.height=3;
CvTermCriteria criteria;
criteria.type=CV_TERMCRIT_ITER;
criteria.max_iter=1000;
criteria.epsilon=0.1;
cvSnakeImage( image, point,length,&alpha,&beta,&gamma,CV_VALUE,size,criteria,0 ); //显示曲线
for(int i=0;i<length;i++)
{
int j = (i+1)%length;
cvLine( image2, point[i],point[j],CV_RGB( 0, 255, 0 ),1,8,0 );
}
delete []point; } int main(int argc, char* argv[])
{ cvNamedWindow("win1",0);
cvCreateTrackbar("Thd", "win1", &Thresholdness, 255, onChange);
cvCreateTrackbar("alpha", "win1", &ialpha, 100, onChange);
cvCreateTrackbar("beta", "win1", &ibeta, 100, onChange);
cvCreateTrackbar("gamma", "win1", &igamma, 100, onChange);
cvResizeWindow("win1",300,500);
onChange(0); for(;;)
{
if(cvWaitKey(40)==27) break;
cvShowImage("win1",image2);
} return 0;
}

转:http://shi-xj.blog.163.com/blog/static/3178051520110911234254/

openCV中cvSnakeImage()函数代码分析的更多相关文章

  1. (转)x264源码分析(1):main、parse、encode、x264_encoder_open函数代码分析

    转自:http://nkwavelet.blog.163.com/blog/static/2277560382013103010312144/ x264版本:   x264-snapshot-2014 ...

  2. 立体视觉-opencv中立体匹配相关代码

    三种匹配算法比较 BM算法: 该算法代码: view plaincopy to clipboardprint? CvStereoBMState *BMState = cvCreateStereoBMS ...

  3. 混合高斯模型:opencv中MOG2的代码结构梳理

    /* 头文件:OurGaussmix2.h */ #include "opencv2/core/core.hpp" #include <list> #include&q ...

  4. OpenCV中phase函数计算方向场

    一.函数原型 ​该函数参数angleInDegrees默认为false,即弧度,当置为true时,则输出为角度. phase函数根据函数来计算角度,计算精度大约为0.3弧度,当x,y相等时,angle ...

  5. OpenCV中threshold函数的使用

    转自:https://blog.csdn.net/u012566751/article/details/77046445 一篇很好的介绍threshold文章: 图像的二值化就是将图像上的像素点的灰度 ...

  6. 大数据学习之Scala中main函数的分析以及基本规则(2)

    一.main函数的分析 首先来看我们在上一节最后看到的这个程序,我们先来简单的分析一下.有助于后面的学习 object HelloScala { def main(args: Array[String ...

  7. Opencv中直方图函数calcHist

    calcHist函数在Opencv中是极难理解的一个函数,一方面是参数说明晦涩难懂,另一方面,说明书给出的实例也不足以令人完全搞清楚该函数的使用方式.最难理解的是第6,7,8个参数dims.histS ...

  8. AnimationsDemo中的ZoomActivity代码分析

    AnimationsDemo是android官网的一个动画使用示例. ZoomActivity是demo中的图像缩放动画,因为这种效果比较常见,所以研究了一下代码. 下面是效果图: 毫无疑问这是一个组 ...

  9. 5. openCV中常用函数学习

    一.前言 经过两个星期的努力,一边学习,一边写代码,初步完成了毕业论文系统的界面和一些基本功能,主要包括:1 数据的读写和显示,及相关的基本操作(放大.缩小和移动):2 样本数据的选择:3 数据归一化 ...

随机推荐

  1. Sql语句中使用参数化的Top

    在sql中使用参数化的Top,Top后面的参数要用括号括起来. 例如: select top (@ts) ID, [Type], Title, Content, LinkMan, Tel, Check ...

  2. 05-UIKit(UITableViewController)

    目录: 一.UITableViewController(表视图控制器) 二.委托协议 三.tableview工作过程(三问一响应) 四.UITableViewCell 回到顶部 一.UITableVi ...

  3. Rfc2898DeriveBytes解密如何通过java实现

    原文 Rfc2898DeriveBytes解密如何通过java实现 这个找了半天,还是不太懂,密码一点不懂,直接上来问了 Rfc2898DeriveBytes对应的是PBKDF2WithHmacSHA ...

  4. 分享非常有用的Java程序 (关键代码) (二)---列出文件和目录

    原文:分享非常有用的Java程序 (关键代码) (二)---列出文件和目录 File dir = new File("directoryName"); String[] child ...

  5. runnable与handler结合使用,其实跟在Thread中的run()中sleep的效果是一样的

    这是一种可以创建多线程消息的函数使用方法:1,首先创建一个Handler对象Handler handler=new Handler();2,然后创建一个Runnable对象Runnable runna ...

  6. JVM参数说明(转)

    做了这么多年java,自以为算是熟悉,其实还差得远,啥也别说了,还是踏踏实实地学吧.今天总结一下常用的JVM的启动参数. 参数类别 参数项 说明 标准参数(-,所有的JVM实现都必须实现这些参数的功能 ...

  7. linux服务之NFS和SAMBA服务

    这几种网络文件传输最适合局域网.网络中用FTP 一:NFS服务 nfs(network file system)网络文件系统,改服务依赖于rpcbind服务.client通过rpc訪问server端的 ...

  8. 使用struts2和poi导出excel文档

    poi眼下应该是比較流行的操作excel的工具了.这几天做了个struts2和poi结合使用来实现导出excel的功能.个人认为还是比較有用的.代码阅读起来也非常easy.下来就来分享下我的心得 1  ...

  9. hdu 1075 What Are You Talking About(字典树)

    刚学的字典树,代码写得很不熟练.写法上也没有什么特别的优化,就是以1A为第一目标! 可惜还是失败了. 少考虑了一种情况,就是一个单词是另一个单词前缀的问题,写了好久,还是没有1A.不过感觉对字典树有了 ...

  10. 阿里云CentOS配置iptables防火墙[转]

    虽说阿里云推出了云盾服务,但是自己再加一层防火墙总归是更安全些,下面是我在阿里云vps上配置防火墙的过程,目前只配置INPUT.OUTPUT和FORWORD都是ACCEPT的规则 一.检查iptabl ...