zoukankan      html  css  js  c++  java
  • 2017-5-28圆弧检测(opencv-qt)

    F:学科、技能、编程【编程-文件proj圆弧检测(opencv-qt)

    可以自动或者手动测量圆弧液柱的角度:

    使用说明 :

     找圆心(最小二乘拟合)相关代码

    #include <iostream>
    #include <opencv2/opencv.hpp>
    
    using namespace std;
    using namespace cv;
    
    bool circleLeastFit(CvSeq* points, double &center_x, double &center_y, double &radius);//最小二乘法拟合函数
    
    
    int main()
    {
        const char* winname  ="winname";
        //const char* winname1  ="winname1";
        //const char* winname2  ="winname2";
        //const char* winname3  ="winname3";
        char * picname = "P11.jpg";
        //加载原图
        IplImage * pImage = cvLoadImage(picname);
    
        //分量图像
        IplImage *pR = cvCreateImage(cvGetSize(pImage),IPL_DEPTH_8U,1);    
        IplImage *pG = cvCreateImage(cvGetSize(pImage),IPL_DEPTH_8U,1);    
        IplImage *pB = cvCreateImage(cvGetSize(pImage),IPL_DEPTH_8U,1);  
    
        IplImage *temp = cvCreateImage(cvGetSize(pImage),IPL_DEPTH_8U,1);  
        IplImage *binary = cvCreateImage(cvGetSize(pImage),IPL_DEPTH_8U,1); 
        //trackbar的变量值    //对应各个通道
        int b_low =20;
        int b_high = 100;
        int g_low = 20;
        int g_high = 100;
        int r_low = 0;
        int r_high = 100;
    
        //轮廓相关
        CvMemStorage *storage = cvCreateMemStorage(0);  
        CvSeq * seq = cvCreateSeq(CV_SEQ_ELTYPE_POINT, sizeof(CvSeq), sizeof(CvPoint), storage);
    
        //窗口
        cvNamedWindow(winname);        
        cvShowImage(winname, pImage);  //显示原图
        cvNamedWindow("r",2);  
        cvNamedWindow("g",2); 
        cvNamedWindow("b",2); //各个通道
        cvNamedWindow("binary",2);//二值化图
    
        //在相应的窗口建立滑动条
        cvCreateTrackbar(  "b1","b", &b_low,  254,   NULL); //H通道分量范围0-180
        cvSetTrackbarPos("b1","b",0 );                        //设置默认位置
        cvCreateTrackbar(  "b2","b", &b_high,  254,   NULL);//H通道分量范围0-180
        cvSetTrackbarPos("b2","b",110 );
    
        cvCreateTrackbar(  "g1","g", &g_low,  254,   NULL);
        cvSetTrackbarPos("g1","g",0 );
        cvCreateTrackbar(  "g2","g", &g_high,  254,   NULL);
        cvSetTrackbarPos("g2","g",158 );
    
        cvCreateTrackbar(  "r1","r", &r_low,  254,   NULL);
        cvSetTrackbarPos("r1","r",68 );
        cvCreateTrackbar(  "r2","r", &r_high,  254,   NULL);
        cvSetTrackbarPos("r2","r",137);
    
        while(1)
        {
            //各个通道分离 
            cvSplit(pImage,pB,pG,pR,NULL);
    
            //阈值化 
            cvThreshold(pB, temp,b_low , 255, CV_THRESH_BINARY);
            cvThreshold(pB, pB,b_high , 255, CV_THRESH_BINARY_INV);
            cvAnd(temp,pB,pB,NULL);//与操作,合成一张图
    
            cvThreshold(pG, temp,g_low , 255, CV_THRESH_BINARY);
            cvThreshold(pG, pG,g_high , 255, CV_THRESH_BINARY_INV);
            cvAnd(temp,pG,pG,NULL);//与操作,合成一张图
    
            cvThreshold(pR, temp,r_low , 255, CV_THRESH_BINARY);
            cvThreshold(pR, pR,r_high , 255, CV_THRESH_BINARY_INV);
            cvAnd(temp,pR,pR,NULL);//与操作,合成一张图
    
            //显示各个通道的图像
            cvShowImage("b",pB);  
            cvShowImage("g",pG);  
            cvShowImage("r",pR); 
    
            //合成到一张图里
            cvAnd(pB, pG, binary, NULL);
            cvAnd(pR, binary, binary, NULL);
    
            //膨胀腐蚀操作去除黑点
            //cvDilate(binary,binary);
            //cvErode(binary,binary);
    
            //显示合成的二值化图
            cvShowImage("binary",binary);
            //cvSaveImage("erzhitu.jpg",binary);
    
            // 处理轮廓 
            int cnt = cvFindContours(binary,storage,&seq,sizeof(CvContour), CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);//返回轮廓的数目
            CvSeq* _contour =seq; 
            cout<<"number of contours "<<cnt<<endl; 
    ////////////////////_
            //找到长度最大轮廓; 
            double maxarea=0;
            int ind_max = -1;
            int m=0;
             for( ; seq != 0; seq = seq->h_next )
             {
                 m++;
                double tmparea = abs(cvArcLength(seq,CV_WHOLE_SEQ,-1));
                  //double contArea = fabs(cvContourArea(pcontour,CV_WHOLE_SEQ));
                if(tmparea > maxarea)
                {
                    maxarea = tmparea;
                    ind_max=m;
                }
                // cout<<"seqfor:  "<<seq->total<<endl;
             }
             m=0;
             seq = _contour;
             for( ; seq != 0; seq = seq->h_next )
             {
                m++;
                if(m == ind_max)
                {
                    break;
                }
             }
             CvSeq*  cur_cont = seq;
             cout<<"seq:  "<<seq->total<<endl;
             cout<<"cur_cont:  "<<cur_cont->total<<endl;
             //for (int i=0;i<cur_cont->total;++i)
             //{
                // CvPoint* p = CV_GET_SEQ_ELEM(CvPoint,cur_cont,i);//输出轮廓上点的坐标
                // printf("(%d,%d)
    ",p->x,p->y);
             //}
             //cvWaitKey(0);
    
             //建立彩色输出图像
             IplImage *pOutlineImage = cvCreateImage(cvGetSize(pImage), IPL_DEPTH_8U, 3);  
             cvCopy(pImage,pOutlineImage);
             
             //int nLevels = 5; 
             //获取最大轮廓的凸包点集
             CvSeq* hull=NULL;
             hull = cvConvexHull2(cur_cont,0,CV_CLOCKWISE,0);  
             cout<<"hull total points number:"<<hull->total<<endl;
             CvPoint pt0 = **(CvPoint**)cvGetSeqElem(hull,hull->total - 1);  
             for(int i = 0;i<hull->total;++i){  
                 CvPoint pt1 = **(CvPoint**)cvGetSeqElem(hull,i);  
                 cvLine(pOutlineImage,pt0,pt1,CV_RGB(0,0,255));  
                 pt0 = pt1;  
             }  
    
             //最小二乘法拟合圆
             double center_x=0;
             double center_y=0;
             double radius=0;
             cout<<"nihe :"<<circleLeastFit(hull, center_x, center_y, radius);
             cout<<"canshu: "<<center_x<<endl<<center_y<<endl<<radius<<endl;
             
             //绘制圆
             cvCircle(pOutlineImage,Point2f(center_x,center_y),radius,CV_RGB(0,100,100));
    
    //////////////////////////////////////////////////////////////////////////
    
            //绘制轮廓
            //cvDrawContours(pOutlineImage, cur_cont, CV_RGB(255,0,0), CV_RGB(0,255,0),0);  
            //cvDrawContours(dst,contour,CV_RGB(255,0,0),CV_RGB(0,255,0),0); 
            cvShowImage(winname, pOutlineImage);  //显示原图jiangshang luokuo
    
            if (cvWaitKey(1000) == 27)
            {
                cvSaveImage("tutu.jpg",pOutlineImage);
    
                break;
            }
            cvClearMemStorage( storage );  //清除轮廓所占用的内存
            cvReleaseImage(&pOutlineImage);//清除彩色输出图像
        }
    
        cvDestroyAllWindows();
        cvReleaseImage(&pImage);
        cvReleaseImage(&pR);    
        cvReleaseImage(&pG);    
        cvReleaseImage(&pB);    
        cvReleaseImage(&temp);
        cvReleaseImage(&binary);
        return 0;
    }
    
    //最小二乘法拟合,输出圆心的xy坐标值和半径大小;
    bool circleLeastFit(CvSeq* points, double &center_x, double &center_y, double &radius)
    {
        center_x = 0.0f;
        center_y = 0.0f;
        radius = 0.0f;
        if (points->total < 3)
        {
            return false;
        }
    
        double sum_x = 0.0f, sum_y = 0.0f;
        double sum_x2 = 0.0f, sum_y2 = 0.0f;
        double sum_x3 = 0.0f, sum_y3 = 0.0f;
        double sum_xy = 0.0f, sum_x1y2 = 0.0f, sum_x2y1 = 0.0f;
    
        int N = points->total ;
        for (int i = 0; i < N; i++)
        {
             CvPoint pt1 = **(CvPoint**)cvGetSeqElem(points,i); 
            double x =pt1.x;
            double y = pt1.y ;
            double x2 = x * x;
            double y2 = y * y;
            sum_x += x;
            sum_y += y;
            sum_x2 += x2;
            sum_y2 += y2;
            sum_x3 += x2 * x;
            sum_y3 += y2 * y;
            sum_xy += x * y;
            sum_x1y2 += x * y2;
            sum_x2y1 += x2 * y;
        }
    
        double C, D, E, G, H;
        double a, b, c;
    
        C = N * sum_x2 - sum_x * sum_x;
        D = N * sum_xy - sum_x * sum_y;
        E = N * sum_x3 + N * sum_x1y2 - (sum_x2 + sum_y2) * sum_x;
        G = N * sum_y2 - sum_y * sum_y;
        H = N * sum_x2y1 + N * sum_y3 - (sum_x2 + sum_y2) * sum_y;
        a = (H * D - E * G) / (C * G - D * D);
        b = (H * C - E * D) / (D * D - G * C);
        c = -(a * sum_x + b * sum_y + sum_x2 + sum_y2) / N;
    
        center_x = a / (-2);
        center_y = b / (-2);
        radius = sqrt(a * a + b * b - 4 * c) / 2;
        return true;
    }

    标定相关代码

    #include "opencv2/core/core.hpp"  
    #include "opencv2/imgproc/imgproc.hpp"  
    #include "opencv2/calib3d/calib3d.hpp"  
    #include "opencv2/highgui/highgui.hpp"  
    #include <iostream>  
    #include <fstream>  
      
    using namespace cv;  
    using namespace std;  
      
    #define MAX_GRAY_VALUE 255
    #define MIN_GRAY_VALUE 0
    using namespace cv;
    using namespace std;
    
    #include <opencv2/imgproc/imgproc.hpp>
    #include <iostream>
    #include <stdio.h>
    using namespace std;
    using namespace cv;
    
    bool check_line_state=false;
    IplImage* workImg;
    IplImage* imgshow;
    CvRect ROI_rect;
    
    IplImage* src=0;  
    void on_mouse( int event, int x, int y, int flags, void* ustc)  
    {  
        
        CvFont font;  
        cvInitFont(&font, CV_FONT_HERSHEY_SIMPLEX, 0.5, 0.5, 0, 1, CV_AA);  
              
        if( event == CV_EVENT_LBUTTONDOWN )  
        {  
            CvPoint pt = cvPoint(x,y);  
            char temp[16];  
            sprintf(temp,"(%d,%d)",pt.x,pt.y);  
            cout<<"("<<pt.x<<","<<pt.y<<")"<<endl;
            x1=pt.x;
            y1=pt.y;
            
            cvPutText(src,temp, pt, &font, cvScalar(255, 255, 255, 0));  
            cvCircle( src, pt, 2,cvScalar(255,0,0,0) ,CV_FILLED, CV_AA, 0 );  
            cvShowImage( "src", src ); 
            
        }   
    }  
    
    int main()  
    {  
        //获取端点的坐标
        src=cvLoadImage("dst7.png",1);  
      
        cvNamedWindow("src",1);  
        cvSetMouseCallback( "src", on_mouse, 0 );  
        
        
        cvShowImage("src",src);  
        cvWaitKey(0);   
        cvDestroyAllWindows();  
        cvReleaseImage(&src);  
      
        return 0;  
    }  
    
    
    /*
    //寻找圆心坐标
    int main(int args,char** argv)
    {   static double radius;
        static int i;
        Mat srcImage = imread("dst7.png");
        if (!srcImage.data)
            return -1;
        imshow("srcImage", srcImage);
        Mat srcGray;
        cvtColor(srcImage, srcGray, COLOR_BGR2GRAY);
        //高斯平滑滤波
        GaussianBlur(srcGray, srcGray, Size(9, 9), 2,2);
        static vector<Vec3f> circles;
        //Hough圆检测
        HoughCircles(srcGray, circles, CV_HOUGH_GRADIENT,1,srcGray.rows/8,200,16,0,0);
        //将得到的结果绘图
        for (size_t i = 0; i < circles.size(); i++)
        {
            Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
            cout<<center<<endl;
            radius = cvRound(circles[i][2]);
            cout<<radius<<endl;
            //检测圆中心
            circle(srcImage, center, 3, Scalar(0, 255, 0), -1, 8, 0);
            //检测圆轮廓
            circle(srcImage, center, radius, Scalar(120, 120, 120), 3, 8, 0);
        }
        imshow("HoughResult", srcImage);
        imwrite("HoughResult.jpg",srcImage);
    
    
    
        IplImage* image=cvLoadImage("dst5.png");
    
        int p=0;
        int q=0;
    
        for (int k=0;k<=360;k++)
        {  
                  double m = 3.1415926535*2*k/360;
                  CvScalar s;
                  s=cvGet2D(image,cvRound(circles[i][0])+radius*cos(m),cvRound(circles[i][1])+radius*sin(m));
                 if(s.val[0]!=255)
                  {
                      p++;
                      q++;
                   }
                 else 
                     q++;
                  
                 
        
                 cout<<m<<p<<q<<endl;
                 
              
    
        }
        
        waitKey(0);
        return 0;
     
    }
    
    
    //二值化部分
    //otsu函数计算最佳阈值
    int otsu(Mat dst){  
      
        int i, j;  
        int tmp;  
      
        double u0, u1, w0, w1, u, uk;  
      
        double cov;  
        double maxcov = 0.0;  
        int maxthread = 0;  
      
        int hst[MAX_GRAY_VALUE] = { 0 };  
        double pro_hst[MAX_GRAY_VALUE] = { 0.0 };  
      
        int height = dst.cols;  
        int width = dst.rows;  
      
        //统计每个灰度的数量  
        for (i = 0; i<width; i++){  
            for (j = 0; j<height; j++){  
                tmp = dst.at<uchar>(i, j);  
                hst[tmp]++;  
            }  
        }  
      
        //计算每个灰度级占图像中的概率  
        for (i = MIN_GRAY_VALUE; i<MAX_GRAY_VALUE; i++)  
            pro_hst[i] = (double)hst[i] / (double)(width*height);  
      
        //计算全局平均灰度值  
        u = 0.0;  
        for (i = MIN_GRAY_VALUE; i<MAX_GRAY_VALUE; i++)  
            u += i*pro_hst[i];  
      
      
        //统计前景和背景的平均灰度值,并计算类间方差  
      
        for (i = MIN_GRAY_VALUE; i<MAX_GRAY_VALUE; i++){  
      
            w0 = 0.0; w1 = 0.0; u0 = 0.0; u1 = 0.0; uk = 0.0;  
      
            for (j = MIN_GRAY_VALUE; j < i; j++){  
      
                uk += j*pro_hst[j];  
                w0 += pro_hst[j];//前景占图像画幅比例  
      
            }  
            u0 = uk / w0;//前景平均灰度  
            w1 = 1 - w0;//背景占图像画幅比例  
            u1 = (u - uk) / (1 - w0);//背景平均灰度  
      
            //计算类间方差  
            cov = w0*w1*(u1 - u0)*(u1 - u0);  
      
            if (cov > maxcov)  
            {  
                maxcov = cov;  
                maxthread = i;  
            }  
        }  
      
        cout << maxthread << endl;  
        return maxthread;  
    }  
    
    
    
    int main(){  
        int width, height;  
        int i, j;  
        Mat obj = imread("22.jpg");  
      
        Mat dst1;  
        cvtColor(obj, dst1, CV_RGB2GRAY);//灰度化  
          
        height = dst1.cols;//计算图像高度  
        width = dst1.rows;//计算图像宽度  
        int thd = otsu(dst1);  
        imshow("原图", dst1);  
      
        for (i = 0; i < width; i++)  
        for (j = 0; j< height; j++)  
        if (dst1.at<uchar>(i, j) > thd)  
            dst1.at<uchar>(i, j) = MAX_GRAY_VALUE-1;  
        else  
            dst1.at<uchar>(i, j) = MIN_GRAY_VALUE;
        imwrite("dst1.png",dst1);
        imshow("二值化", dst1);
    
          
    //膨胀(闭运算消除内部米粒)
        Mat dst2=imread("dst1.png");
        Mat dst3;
        Mat element = getStructuringElement(MORPH_RECT,Size(3,3));
        //imshow("闭运算消除内部空隙 原图", dst2);
        dilate( dst2,dst3,element); //膨胀 
        imshow("闭运算消除内部空隙 效果图", dst3);
        imwrite("dst3.png",dst3);
    
    
    //腐蚀(开运算去除毛刺)
        Mat dst4=imread("dst3.png");
        Mat dst5;
        //imshow("开运算去除毛刺 原图",dst4);
        erode(dst4,dst5,element);
        imshow("开运算去除毛刺 效果图",dst5);
        imwrite("dst5.png",dst5);
    
    //边缘检测
        Mat dst6=imread("dst5.png");
        Mat dst7;
        //imshow("边缘检测 原图",dst6);
        Canny(dst6,dst7,150.100,3);
        imshow("边缘检测 效果图",dst7);
        imwrite("dst7.png",dst7);
    
    
        
     
    
    
        waitKey(0);  
        return 0;  
    }
    
    int main()
    {
        cv::Mat image, Extractcorner;
        cv::vector<cv::Point2f> corners;    //用来储存所有角点坐标
        cv::Size board_size = cv::Size(7, 7);   //标定板每行,每列角点数
        image = cv::imread("2.jpg");
        Extractcorner = image.clone();
    
        cv::Mat imageGray;
        cv::cvtColor(image, imageGray, CV_RGB2GRAY);
        bool patternfound = cv::findChessboardCorners(image, board_size, corners, cv::CALIB_CB_FAST_CHECK + cv::CALIB_CB_ADAPTIVE_THRESH + cv::CALIB_CB_NORMALIZE_IMAGE);
        if (!patternfound)
        {
            std::cout << "can not find chessboard corners!" << std::endl;
            exit(1);
        }
        else
        {
            //亚像素精确化
            cv::cornerSubPix(imageGray, corners, cv::Size(11, 11), cv::Size(-1, -1), cv::TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 30, 0.1));
        }
    
        //角点检测图像显示
        for (int i = 0; i < corners.size(); i++)
        {
            cv::circle(Extractcorner, corners[i], 5, cv::Scalar(255, 0, 255), 2);
        }
        cv::imshow("Extractcorner", Extractcorner);
        cv::imwrite("Extractcorner.jpg", Extractcorner);
    //输出角点坐标
        cout<<corners<<endl;
    
    //参考图像
        cv::Mat image2, Extractcorner2;
        cv::vector<cv::Point2f> corners2;    //用来储存所有角点坐标
        cv::Size board_size2 = cv::Size(7, 7);   //标定板每行,每列角点数
        image2 = cv::imread("1.jpg");
        Extractcorner2 = image2.clone();
    
        cv::Mat imageGray2;
        cv::cvtColor(image2, imageGray2, CV_RGB2GRAY);
        bool patternfound2 = cv::findChessboardCorners(image2, board_size, corners2, cv::CALIB_CB_FAST_CHECK + cv::CALIB_CB_ADAPTIVE_THRESH + cv::CALIB_CB_NORMALIZE_IMAGE);
        if (!patternfound2)
        {
            std::cout << "can not find chessboard corners!" << std::endl;
            exit(1);
        }
        else
        {
            //亚像素精确化
            cv::cornerSubPix(imageGray2, corners2, cv::Size(11, 11), cv::Size(-1, -1), cv::TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 30, 0.1));
        }
    
        //角点检测图像显示
        for (int i = 0; i < corners2.size(); i++)
        {
            cv::circle(Extractcorner2, corners2[i], 5, cv::Scalar(255, 0, 255), 2);
        }
        cv::imshow("Extractcorner2", Extractcorner2);
        cv::imwrite("Extractcorner2.jpg", Extractcorner2);
    //输出角点坐标
        cout<<corners2<<endl;
    
    
    //仿射变换1
        Mat src = imread("2.jpg");
        Mat dst_warp;
       Point2f srcPoints[3];//原图中的三点
       Point2f dstPoints[3];//目标图中的三点
     
        //三个点对的值
        srcPoints[0] = Point2f(142.52786,115.98566);
        srcPoints[1] = Point2f(110.28358,409.29211);
        srcPoints[2] = Point2f(438.46851,126.58415);
    
        dstPoints[0] = Point2f(44.506947, 46.233685);
        dstPoints[1] = Point2f(44.496399, 325.76706);
        dstPoints[2] = Point2f(314.50659, 46.230354);
    
       Mat M1 = getAffineTransform(srcPoints,dstPoints);//由三个点对计算变换矩阵
       warpAffine(src,dst_warp,M1,src.size());//仿射变换
     
        imshow("src",src);
       imshow("dst_warp",dst_warp);
       imwrite("dst_warp.jpg",dst_warp);
    
    //一次变换后图像
        cv::Mat image3, Extractcorner3;
        cv::vector<cv::Point2f> corners3;    //用来储存所有角点坐标
        cv::Size board_size3 = cv::Size(7, 7);   //标定板每行,每列角点数
        image3 = cv::imread("dst_warp.jpg");
        Extractcorner3 = image3.clone();
    
        cv::Mat imageGray3;
        cv::cvtColor(image3, imageGray3, CV_RGB2GRAY);
        bool patternfound3 = cv::findChessboardCorners(image3, board_size, corners3, cv::CALIB_CB_FAST_CHECK + cv::CALIB_CB_ADAPTIVE_THRESH + cv::CALIB_CB_NORMALIZE_IMAGE);
        if (!patternfound3)
        {
            std::cout << "can not find chessboard corners!" << std::endl;
            exit(1);
        }
        else
        {
            //亚像素精确化
            cv::cornerSubPix(imageGray3, corners3, cv::Size(11, 11), cv::Size(-1, -1), cv::TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 30, 0.1));
        }
    
        //角点检测图像显示
        for (int i = 0; i < corners3.size(); i++)
        {
            cv::circle(Extractcorner3, corners3[i], 5, cv::Scalar(255, 0, 255), 2);
        }
        cv::imshow("Extractcorner3", Extractcorner3);
        cv::imwrite("Extractcorner3.jpg", Extractcorner3);
    
    //输出角点坐标
        cout<<corners3<<endl;
    
    
        ofstream outfile;
        outfile.open("date.txt");
        outfile<<corners<<endl<<endl<<endl<<corners2<<corners3<<endl;
        outfile.close();
            
    //仿射变换2
        Mat src2 = imread("dst_warp.jpg");
        Mat dst_warp2;
       Point2f src2Points[3];//原图中的三点
       Point2f dst2Points[3];//目标图中的三点
     
        //三个点对的值
        src2Points[0] = Point2f(395.12207, 306.01523);
        src2Points[1] = Point2f(44.515686, 325.73227);
        src2Points[2] = Point2f(314.53482, 46.279831);
    
        dst2Points[0] = Point2f(314.49469, 325.76535);
        dst2Points[1] = Point2f(44.496399, 325.76706);
        dst2Points[2] = Point2f(314.50659, 46.230354);
    
       Mat M2 = getAffineTransform(src2Points,dst2Points);//由三个点对计算变换矩阵
       warpAffine(src2,dst_warp2,M2,src2.size());//仿射变换
     
        imshow("src2",src);
       imshow("dst_warp2",dst_warp2);
       imwrite("dst_warp2.jpg",dst_warp2);
        cv::waitKey(0);
    
        return 0;
    }
    */
  • 相关阅读:
    文件内部写入及读取(参考疯狂安卓讲义)
    API内部文件读取
    内部存储文件(读)
    内部存储文件(写)
    短信发送器(1.0版)
    按钮点击的三种方法及推广
    struts标签错误:Can not find the tag library descriptor for "http://java.sun.com/jsp/jstl/core"
    java中16进制转换10进制
    java project转变成java web project
    oracle,sqlserver,mysql常见数据库jdbc连接
  • 原文地址:https://www.cnblogs.com/tangyuanjie/p/12924193.html
Copyright © 2011-2022 走看看