2018-11-17 22:33:28 qq_34586921 阅读数 11963
  • 学习OpenCV3.2+QT5+ffmpeg实战开发视频编辑器视频教程

    OpenCV3.2+QT5+ffmpeg实战开发视频编辑器视频培训课程概况:教程中会讲解到基于opencv视频和摄像机录制、播放和播放进度控制,多视频图像合并、多视频图像融合、剪切、视频亮度、对比度、尺寸(近邻插值(手动实现),双线性插值,图像金字塔)、颜色格式(灰度图,二值化(阈值)),旋转镜像,视频裁剪(ROI),视频水印(ROI+weight),导出处理后的视频(包含音频,使用ffmpeg工具对音频进行抽取、剪切和终于opencv处理的视频合并)。

    20633 人正在学习 去看看 夏曹俊

前言

上节课学习了实现图像旋转的原理,下课后用matlab实现了一下图像旋转的功能,这里做个记录。


图像旋转原理

图像旋转的本质利用的是向量的旋转。

矩阵乘法的实质是进行线性变换,因此对一个向量进行旋转操作也可以通过矩阵和向量相乘的方式进行。

【ps:线性代数的本质这个视频很直观地解释了各种线性代数运算的实质,链接:https://www.bilibili.com/video/av6731067

因为图像都是通过二维矩阵存放的(单通道),所以对图像进行旋转时要先设定一个像素作为旋转轴,然后其他的像素位置可以看作从旋转轴出发的向量。

如图中间的红点为旋转轴,则旋转的实质就是将图中的各个向量进行旋转,然后将旋转前的位置的像素值赋值给旋转后的位置的像素值。

假设有二维向量v = [x ; y],若要进行逆时针旋转角度a。则旋转矩阵R为

旋转后的向量v2 = R * v。

在正式处理过程中可以这么表示,原像素位置记为p,中心点记为c,旋转后像素位置记为pp

则有(pp - c) = R*(p - c)

pp = R*(p-c) + c


代码实现过程

一共写了三份代码,依次改进了旋转图像的效果。

第一次实现代码

第一次实现代码的思路是正向的思路,也就是把原图进行向量的旋转,找到旋转后的向量的位置,然后将原图的像素值赋值过去即可。

代码实现

% 读入图片
im = imread('1.jpg');

% 求出旋转矩阵
a = 30 / 180 * pi;
R = [cos(a), -sin(a); sin(a), cos(a)];

% 求出图片大小 ch为通道数 h为高度 w为宽度
sz = size(im);
h = sz(1);
w = sz(2);
ch = sz(3);
c = [h; w] / 2;

% 初始化结果图像
im2 = uint8(zeros(h, w, 3));
for k = 1:ch
    for i = 1:h
       for j = 1:w
          p = [i; j];
          % round为四舍五入
          pp = round(R*(p-c)+c);
          if (pp(1) >= 1 && pp(1) <= h && pp(2) >= 1 && pp(2) <= w)
              im2(pp(1), pp(2), k) = im(i, j, k); 
          end
       end
    end
end

% 显示图像
figure;
imshow(im2);

结果显示

原图:     旋转后:

分析:可以看到有这么几个瑕疵,首先是图像的大小和原图一样导致边缘被裁剪了,其次是图像中会出现很多噪声很多杂点,出现杂点的原因是从原图旋转后的像素位置在原图可能找不到,解决方法是用逆向思维,从目标图片反向旋转到原图进行像素查找。

第二次实现代码

这次我先算出了旋转后要显示完整图像所需的画布大小,然后像素赋值的顺序反过来,从目标图片反向旋转到原图进行像素查找。此外还要注意,在改变目标画布大小后,图像中心点即旋转轴改变了,要单独进行计算。

% 读入图片
im = imread('1.jpg');

% 求出旋转矩阵
a = 30 / 180 * pi;
R = [cos(a), -sin(a); sin(a), cos(a)];
R = R'; % 求出旋转矩阵的逆矩阵进行逆向查找

% 计算原图大小
sz = size(im);
h = sz(1);
w = sz(2);
ch = sz(3);
c1 = [h; w] / 2;

% 计算显示完整图像需要的画布大小
hh = floor(w*sin(a)+h*cos(a))+1;
ww = floor(w*cos(a)+h*sin(a))+1;
c2 = [hh; ww] / 2;

% 初始化目标画布
im2 = uint8(ones(hh, ww, 3)*128);
for k = 1:ch
    for i = 1:hh
       for j = 1:ww
          p = [i; j];
          pp = round(R*(p-c2)+c1);
          % 逆向进行像素查找
          if (pp(1) >= 1 && pp(1) <= h && pp(2) >= 1 && pp(2) <= w)
             im2(i, j, k) = im(pp(1), pp(2), k); 
          end
       end
    end
end

% 显示图像
figure;
imshow(im2);

结果显示

原图:     旋转后:

分析:可以看到噪声已经消失,同时显示的也是完整的旋转图像。但是这里的插值方式十分简陋,是直接用四舍五入的,还可以再次改进,通过使用线性插值的方法:https://blog.csdn.net/qq_34586921/article/details/84192850

第三次代码实现

和第二次代码实现比起来就是插值方法改变了,其他的都没有改变,插值方法改变后旋转后的图像质量更好了。

% 读入图片
im = imread('1.jpg');

% 求出旋转矩阵
a = 30 / 180 * pi;
R = [cos(a), -sin(a); sin(a), cos(a)];
R = R'; % 求出旋转矩阵的逆矩阵进行逆向查找

% 计算原图大小
sz = size(im);
h = sz(1);
w = sz(2);
ch = sz(3);
c1 = [h; w] / 2;

% 计算显示完整图像需要的画布大小
hh = floor(w*sin(a)+h*cos(a))+1;
ww = floor(w*cos(a)+h*sin(a))+1;
c2 = [hh; ww] / 2;

% 初始化目标画布
im2 = uint8(ones(hh, ww, 3)*128);
for k = 1:ch
    for i = 1:hh
       for j = 1:ww
          p = [i; j];
          pp = (R*(p-c2)+c1);
          mn = floor(pp);
          ab = pp - mn;
          a = ab(1);
          b = ab(2);
          m = mn(1);
          n = mn(2);
          % 线性插值方法
          if (pp(1) >= 2 && pp(1) <= h-1 && pp(2) >= 2 && pp(2) <= w-1)
             im2(i, j, k) = (1-a)*(1-b)*im(m, n, k) + a*(1-b)*im(m+1, n, k)...
                          + (1-a)*b*im(m, n, k)     + a*b*im(m, n, k);
          end
       end
    end
end

% 显示图像
figure;
imshow(im2);

结果显示:

原图:     旋转后: 


总结

学习不息,继续加油                  

2019-04-26 16:25:59 weixin_44804536 阅读数 134
  • 学习OpenCV3.2+QT5+ffmpeg实战开发视频编辑器视频教程

    OpenCV3.2+QT5+ffmpeg实战开发视频编辑器视频培训课程概况:教程中会讲解到基于opencv视频和摄像机录制、播放和播放进度控制,多视频图像合并、多视频图像融合、剪切、视频亮度、对比度、尺寸(近邻插值(手动实现),双线性插值,图像金字塔)、颜色格式(灰度图,二值化(阈值)),旋转镜像,视频裁剪(ROI),视频水印(ROI+weight),导出处理后的视频(包含音频,使用ffmpeg工具对音频进行抽取、剪切和终于opencv处理的视频合并)。

    20633 人正在学习 去看看 夏曹俊
import numpy as np
import os
import cv2
from math import *


def rotate_images(path, angle):
    image_dir = path
    pathDir = os.listdir(image_dir)
    for s in pathDir:
        newDir = os.path.join(image_dir, s)
        # print(newDir)
        if os.path.isfile(newDir):
            if os.path.splitext(newDir)[1] == ".jpg":
                # lenth = len(newDir)
                # print(lenth)
                filename = int(os.path.basename(newDir)[:-4]) + 270

                """
                imgs = cv2.imread(newDir)
                imgs = skimage.transform.rotate(imgs, angle)
                # now = time.strftime("%Y-%m-%d-%H_%M_%S", time.localtime(time.time()))
                plt.figure("rotated")
                plt.imshow(imgs)
                plt.axis("off")
                plt.savefig("D:/learn/lianxi/python_cnn/save/"+str((i+17)) + ".jpg")
                height, width = img.shape[:2]
                """
                img = cv2.imread(newDir)
                degree = angle
                # 旋转后的尺寸
                height, width = img.shape[:2]
                heightNew = int(width * fabs(sin(radians(degree))) + height * fabs(cos(radians(degree))))
                widthNew = int(height * fabs(sin(radians(degree))) + width * fabs(cos(radians(degree))))

                matRotation = cv2.getRotationMatrix2D((width / 2, height / 2), degree, 1)

                matRotation[0, 2] += (widthNew - width) / 2  # 重点在这步,目前不懂为什么加这步
                matRotation[1, 2] += (heightNew - height) / 2  # 重点在这步

                imgRotation = cv2.warpAffine(img, matRotation, (widthNew, heightNew), borderValue=(255, 255, 255))

                cv2.imwrite("D:/learn/lianxi/python_cnn/save2/"+str(filename) + ".jpg", imgRotation)


def rotate_txt(path, angle):
    image_dir = path
    print(path)
    pathDir = os.listdir(image_dir)
    print(pathDir)
    for s in pathDir:
        newDir = os.path.join(image_dir, s)
        print(newDir)
        if os.path.isfile(newDir):
            if os.path.splitext(newDir)[1] == ".txt":
                file = open(newDir, 'r+')
                filename = int(os.path.basename(newDir)[:-4]) + 270
                # print("+++++++++++++")
                print(filename)
                for line in file.readlines():
                    line = line.strip()  # 去掉每行头尾空白
                    line_split = line.split()
                    # print(line_split)

                    int_line = [float(x) for x in line_split]
                    a = np.array(int_line)
                    print(a)
                    x_center = cos(angle)*(a[1]-0.5)-sin(angle)*(a[2]-0.5)
                    y_center = cos(angle)*(a[2]-0.5)+sin(angle)*(a[1]-0.5)
                    x_w = a[4]
                    y_h = a[3]
                    # new = [line_split[0], x_center, y_center, x_w, y_h]
                    # new_line = [str(x) for x in new]
                    # new_file = open("17_1.txt", "a+")
                    # new_file.writelines(str(new_line)+'\n')
                    new = [line_split[0], x_center+0.5, y_center+0.5, x_w, y_h]
                    new_line = [str(x) for x in new]
                    filename1 = str(filename)
                    new_file = open(filename1+'.txt', "a+")
                    lenth = len(new_line)
                    for i in range(0, lenth):
                        if i == 4:
                            new_file.writelines(str(new_line[i]) + '\n')
                        else:
                            new_file.writelines(str(new_line[i]) + " ")


if __name__ == "__main__":

    # rotate_images("D:/learn/lianxi/python_cnn/imgs/", 180)
    rotate_txt("D:/learn/lianxi/python_cnn/imgs/",  pi * 1)


    # alter(r"D:\learn\lianxi\python_cnn\17.txt", 90)
2019-04-14 07:06:06 weixin_33850890 阅读数 359
  • 学习OpenCV3.2+QT5+ffmpeg实战开发视频编辑器视频教程

    OpenCV3.2+QT5+ffmpeg实战开发视频编辑器视频培训课程概况:教程中会讲解到基于opencv视频和摄像机录制、播放和播放进度控制,多视频图像合并、多视频图像融合、剪切、视频亮度、对比度、尺寸(近邻插值(手动实现),双线性插值,图像金字塔)、颜色格式(灰度图,二值化(阈值)),旋转镜像,视频裁剪(ROI),视频水印(ROI+weight),导出处理后的视频(包含音频,使用ffmpeg工具对音频进行抽取、剪切和终于opencv处理的视频合并)。

    20633 人正在学习 去看看 夏曹俊

注:旋转中心很重要 坐标系为像素,按照像素位置(第(m,n)做为坐标)

以坐标原点为中心旋转的原理:

点p0绕坐标原点逆时针方向旋转θ角度得到点p1.

以任意图形中心点为坐标原点旋转原理:

从上图可知以任意图形中心点为坐标原点旋转我们需要三步:
(1)将坐标系Ⅰ变成坐标系Ⅱ
(2)在坐标系Ⅱ中旋转θ角
(3)将坐标系Ⅱ变成坐标系Ⅰ

(1)将坐标系Ⅰ变成坐标系Ⅱ
由Figure1得到Figure2可知,变换矩阵为:

(2)在坐标系Ⅱ中旋转θ角
见上面以坐标原点为中心旋转的原理
(3)将坐标系Ⅱ变成坐标系Ⅰ

最近邻插值matlab代码

function [ A ] = myimrotate(B,degree,method)                                 %定义旋转函数,degree为要旋转的角度
[r,c,d]=size(B);                                                      %获取输入图像B的行r、列c和通道数d,为了旋转彩色图像所以有必要得到通道数d
nH=round(r*abs(cosd(degree))+c*abs(sind(degree)));                    %旋转图像后得到的新高度,“round()函数四舍五入“
nW=round(c*abs(cosd(degree))+r*abs(sind(degree)));                    %旋转图像后得到的新宽度
A=zeros(nH,nW,d);                                                     %定义生成目标图像的行列以及通道数
M1=[1 0 0;
    0 -1 0;
    -0.5*nW 0.5*nH 1 ];                                  %坐标系变换矩阵M1
M2=[cosd(degree) -sind(degree) 0;
    sind(degree) cosd(degree) 0;
    0 0 1];  %角度旋转变换矩阵M2,我用的是顺时针方向
M3=[1 0 0;
    0 -1 0;
    0.5*c 0.5*r 1];                                      %坐标系变换矩阵M3
    for i=1:nW
        for j=1:nH
            temp=[i j 1]*M1*M2*M3;                                    %得到旋转后的矩阵temp
            y_r=temp(1,2);                                              %y取矩阵temp的第一行第二列,y对应j,为高度
            x_r=temp(1,1);                                              %x取矩阵temp的第一行第一列,x对应i,为宽度
            y=round(y_r);                                               %y四舍五入取整
            x=round(x_r);                                               %x四舍五入取整
           if(x>=1&&x<=c)&&(y>=1&&y<=r)                               %判断的得到的(x,y)点是否在原图像上
                %最近邻插值
               if strcmp(method,'near')
                  A(j,i,:)=B(y,x,:);                                     %将原图像的像素点赋值给对应的旋转后图像上的点
               end                                                       %(”有人疑惑为啥不是A(i,j,:)=B(x,y,:);因为i,x对应的是列,即宽,而j,y对应的是行,即高“),我这里以x为横坐标,y为竖向纵坐标
               %线性插值
               if strcmp(method,'linear')       
                  b = x_r-x;
                  a = y+1-y_r;
                  if(x>=1&&x+1<=c)&&(y>=1&&y+1<=r)
                      
                    
                      P1 = b*B(y, x) + (1-b)*B(y+1, x);
                      P2 = b*B(y, x+1) + (1-b)*B(y+1, x+1);
                      P = a*P1 + (1-a)*P2;
                  else
                      P=B(y,x,:);
                  end
                  A(j,i,:)=P;
               end  
               %三次插值
               if strcmp(method,'trib')    
                   x = floor(x_r);
                   y = floor(y_r);
                            
                   if(x>1&&x+2<=c)&&(y>1&&y+2<=r)     
                       b = x_r-x;
                       a = y_r-y;
                       A_A=[s(1+a) s(a) s(1-a) s(2-a)]; 
                       C=[s(1+b);s(b);s(1-b);s(2-b)]; 
                       B_B=[B(y-1,x-1) B(y-1,x) B(y-1,x+1) B(y-1,x+2)  
                          B(y,x-1)   B(y,x)  B(y,x+1)   B(y,x+2)  
                          B(y+1,x-1)   B(y+1,x) B(y+1,x+1) B(y+1,x+2)  
                          B(y+2,x-1) B(y+2,x) B(y+2,x+1) B(y+2,x+2)];
                      A(j,i,:) = (double(A_A)*double(B_B)*double(C));
%                    else
%                        if x<1
%                            x = x+1;
%                        end
%                        if y<1
%                            y = y+1;
%                        end
%                        A(j,i,:)=B(y,x,:);
                   end
               end
           end   
        end
    end
end
%计算S值
function [ re ] = s(x) 
    x = abs(x);
    if x<1 && x>=0
        re = 1-2*x^2 + x^3;
    end
    if x>=1 &&x<2
        re = 4 - 8*x +5*x^2-x^3;
    end
    if x>=2
        re = 0;
    end
end
复制代码
2018-03-28 14:21:00 weixin_30872337 阅读数 22
  • 学习OpenCV3.2+QT5+ffmpeg实战开发视频编辑器视频教程

    OpenCV3.2+QT5+ffmpeg实战开发视频编辑器视频培训课程概况:教程中会讲解到基于opencv视频和摄像机录制、播放和播放进度控制,多视频图像合并、多视频图像融合、剪切、视频亮度、对比度、尺寸(近邻插值(手动实现),双线性插值,图像金字塔)、颜色格式(灰度图,二值化(阈值)),旋转镜像,视频裁剪(ROI),视频水印(ROI+weight),导出处理后的视频(包含音频,使用ffmpeg工具对音频进行抽取、剪切和终于opencv处理的视频合并)。

    20633 人正在学习 去看看 夏曹俊

如果平面上的点绕原点逆时针旋转θº,则其坐标变换公式为:

                                                                                       x'=xcosθ+ysinθ   y=-xsinθ+ycosθ

 

其中,(x, y)为原图坐标,(x’, y’)为旋转后的坐标。它的逆变换公式为:

                                                                                       x=x'cosθ-y'sinθ   y=x'sinθ+y'cosθ

 

矩阵形式为:

                                                                                     

和缩放类似,旋转后的图像的像素点也需要经过坐标转换为原始图像上的坐标来确定像素值,同样也可能找不到对应点,因此旋转也用到插值法。在此选用性能较好的双线性插值法。为提高速度,在处理旋转90º、-90º、±180º时使用了镜像来处理。

 

 

        /// <summary>
        /// 图像旋转
        /// </summary>
        /// <param name="srcBmp">原始图像</param>
        /// <param name="degree">旋转角度</param>
        /// <param name="dstBmp">目标图像</param>
        /// <returns>处理成功 true 失败 false</returns>
        public static bool Rotation(Bitmap srcBmp, double degree, out Bitmap dstBmp)
        {
            if (srcBmp == null)
            {
                dstBmp = null;
                return false;
            }
            dstBmp = null;
            BitmapData srcBmpData = null;
            BitmapData dstBmpData = null;
            switch ((int)degree)
            {
                case 0:
                    dstBmp = new Bitmap(srcBmp);
                    break;
                case -90:
                    dstBmp = new Bitmap(srcBmp.Height, srcBmp.Width);
                    srcBmpData = srcBmp.LockBits(new Rectangle(0, 0, srcBmp.Width, srcBmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
                    dstBmpData = dstBmp.LockBits(new Rectangle(0, 0, dstBmp.Width, dstBmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
                    unsafe
                    {
                        byte* ptrSrc = (byte*)srcBmpData.Scan0;
                        byte* ptrDst = (byte*)dstBmpData.Scan0;
                        for (int i = 0; i < srcBmp.Height; i++)
                        {
                            for (int j = 0; j < srcBmp.Width; j++)
                            {
                                ptrDst[j * dstBmpData.Stride + (dstBmp.Height - i - 1) * 3] = ptrSrc[i * srcBmpData.Stride + j * 3];
                                ptrDst[j * dstBmpData.Stride + (dstBmp.Height - i - 1) * 3 + 1] = ptrSrc[i * srcBmpData.Stride + j * 3 + 1];
                                ptrDst[j * dstBmpData.Stride + (dstBmp.Height - i - 1) * 3 + 2] = ptrSrc[i * srcBmpData.Stride + j * 3 + 2];
                            }
                        }
                    }
                    srcBmp.UnlockBits(srcBmpData);
                    dstBmp.UnlockBits(dstBmpData);
                    break;
                case 90:
                    dstBmp = new Bitmap(srcBmp.Height, srcBmp.Width);
                    srcBmpData = srcBmp.LockBits(new Rectangle(0, 0, srcBmp.Width, srcBmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
                    dstBmpData = dstBmp.LockBits(new Rectangle(0, 0, dstBmp.Width, dstBmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
                    unsafe
                    {
                        byte* ptrSrc = (byte*)srcBmpData.Scan0;
                        byte* ptrDst = (byte*)dstBmpData.Scan0;
                        for (int i = 0; i < srcBmp.Height; i++)
                        {
                            for (int j = 0; j < srcBmp.Width; j++)
                            {
                                ptrDst[(srcBmp.Width - j - 1) * dstBmpData.Stride + i * 3] = ptrSrc[i * srcBmpData.Stride + j * 3];
                                ptrDst[(srcBmp.Width - j - 1) * dstBmpData.Stride + i * 3 + 1] = ptrSrc[i * srcBmpData.Stride + j * 3 + 1];
                                ptrDst[(srcBmp.Width - j - 1) * dstBmpData.Stride + i * 3 + 2] = ptrSrc[i * srcBmpData.Stride + j * 3 + 2];
                            }
                        }
                    }
                    srcBmp.UnlockBits(srcBmpData);
                    dstBmp.UnlockBits(dstBmpData);
                    break;
                case 180:
                case -180:
                    dstBmp = new Bitmap(srcBmp.Width, srcBmp.Height);
                    srcBmpData = srcBmp.LockBits(new Rectangle(0, 0, srcBmp.Width, srcBmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
                    dstBmpData = dstBmp.LockBits(new Rectangle(0, 0, dstBmp.Width, dstBmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
                    unsafe
                    {
                        byte* ptrSrc = (byte*)srcBmpData.Scan0;
                        byte* ptrDst = (byte*)dstBmpData.Scan0;
                        for (int i = 0; i < srcBmp.Height; i++)
                        {
                            for (int j = 0; j < srcBmp.Width; j++)
                            {
                                ptrDst[(srcBmp.Width - i - 1) * dstBmpData.Stride + (dstBmp.Height - j - 1) * 3] = ptrSrc[i * srcBmpData.Stride + j * 3];
                                ptrDst[(srcBmp.Width - i - 1) * dstBmpData.Stride + (dstBmp.Height - j - 1) * 3 + 1] = ptrSrc[i * srcBmpData.Stride + j * 3 + 1];
                                ptrDst[(srcBmp.Width - i - 1) * dstBmpData.Stride + (dstBmp.Height - j - 1) * 3 + 2] = ptrSrc[i * srcBmpData.Stride + j * 3 + 2];
                            }
                        }
                    }
                    srcBmp.UnlockBits(srcBmpData);
                    dstBmp.UnlockBits(dstBmpData);
                    break;
                default://任意角度
                    double radian = degree * Math.PI / 180.0;//将角度转换为弧度
                                                             //计算正弦和余弦
                    double sin = Math.Sin(radian);
                    double cos = Math.Cos(radian);
                    //计算旋转后的图像大小
                    int widthDst = (int)(srcBmp.Height * Math.Abs(sin) + srcBmp.Width * Math.Abs(cos));
                    int heightDst = (int)(srcBmp.Width * Math.Abs(sin) + srcBmp.Height * Math.Abs(cos));

                    dstBmp = new Bitmap(widthDst, heightDst);
                    //确定旋转点
                    int dx = (int)(srcBmp.Width / 2 * (1 - cos) + srcBmp.Height / 2 * sin);
                    int dy = (int)(srcBmp.Width / 2 * (0 - sin) + srcBmp.Height / 2 * (1 - cos));

                    int insertBeginX = srcBmp.Width / 2 - widthDst / 2;
                    int insertBeginY = srcBmp.Height / 2 - heightDst / 2;

                    //插值公式所需参数
                    double ku = insertBeginX * cos - insertBeginY * sin + dx;
                    double kv = insertBeginX * sin + insertBeginY * cos + dy;
                    double cu1 = cos, cu2 = sin;
                    double cv1 = sin, cv2 = cos;

                    double fu, fv, a, b, F1, F2;
                    int Iu, Iv;
                    srcBmpData = srcBmp.LockBits(new Rectangle(0, 0, srcBmp.Width, srcBmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
                    dstBmpData = dstBmp.LockBits(new Rectangle(0, 0, dstBmp.Width, dstBmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

                    unsafe
                    {
                        byte* ptrSrc = (byte*)srcBmpData.Scan0;
                        byte* ptrDst = (byte*)dstBmpData.Scan0;
                        for (int i = 0; i < heightDst; i++)
                        {
                            for (int j = 0; j < widthDst; j++)
                            {
                                fu = j * cu1 - i * cu2 + ku;
                                fv = j * cv1 + i * cv2 + kv;
                                if ((fv < 1) || (fv > srcBmp.Height - 1) || (fu < 1) || (fu > srcBmp.Width - 1))
                                {

                                    ptrDst[i * dstBmpData.Stride + j * 3] = 150;
                                    ptrDst[i * dstBmpData.Stride + j * 3 + 1] = 150;
                                    ptrDst[i * dstBmpData.Stride + j * 3 + 2] = 150;
                                }
                                else
                                {//双线性插值
                                    Iu = (int)fu;
                                    Iv = (int)fv;
                                    a = fu - Iu;
                                    b = fv - Iv;
                                    for (int k = 0; k < 3; k++)
                                    {
                                        F1 = (1 - b) * *(ptrSrc + Iv * srcBmpData.Stride + Iu * 3 + k) + b * *(ptrSrc + (Iv + 1) * srcBmpData.Stride + Iu * 3 + k);
                                        F2 = (1 - b) * *(ptrSrc + Iv * srcBmpData.Stride + (Iu + 1) * 3 + k) + b * *(ptrSrc + (Iv + 1) * srcBmpData.Stride + (Iu + 1) * 3 + k);
                                        *(ptrDst + i * dstBmpData.Stride + j * 3 + k) = (byte)((1 - a) * F1 + a * F2);
                                    }
                                }
                            }
                        }
                    }
                    srcBmp.UnlockBits(srcBmpData);
                    dstBmp.UnlockBits(dstBmpData);
                    break;
            }
            return true;
        }

 

 

 

 

 

转载于:https://www.cnblogs.com/dearzhoubi/p/8663596.html

NULL

博文 来自: ichangjian
没有更多推荐了,返回首页