CG——Possion Image Editing

Posted Ed_Sheeran

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CG——Possion Image Editing相关的知识,希望对你有一定的参考价值。

博主终于正式回来发文了。

之后会写一些学习心得,大学应该不会打ACM了。

目前尝试CG,兴趣使然,希望后面可以坚持吧。

Possion Image Editing

学习资料:https://blog.csdn.net/u011534057/article/details/68922319

https://zhuanlan.zhihu.com/p/58867397

这两份讲的比较好,但还是看论文比较好,我按第一篇又是算梯度又是算散度,又在想怎么构造转移矩阵,对自己的数学极度怀疑,差点自闭掉。后来经jdr大佬指点发现按照论文的分析,这实际就是一个解方程组的问题,即  div(h) = div(g), 明显是一个高斯消元的方程,但是图像以像素点储存,复杂度明显爆炸,所以可以用迭代的方式解,因为边界是确定的,最后会收敛,复杂度暴降。

简单概括一下泊松:讲目标图像抽象成一个函数h,背景设为f,融合后的图像设为g,我们所做的就是让g看起来就是f上的一个函数。对策就是边界取f的值,g的变化趋势尽量符合h的变化趋势。即

 

遇到的问题:

1.opencv的c++安装:花了两天都没搞定,按照博客一步步做,但是我下载的文件夹和博客下下来的不一样,最后无法写codevs的路径。(中途又在gcc的编译路径中加了空格,真是佩服我自己)=》最后只有选择Python写。(最后意识到我Python烂到和装环境差不多)

2.算法:按照博客老实按论文公式写,对数学要求太高了,好多人居然用到fft...=》请教jdr获得迭代解方程的算法

3.Python运算太慢,迭代还是T=》只有把数据传到C++来处理,果然还是得C

4.图像坐标轴问题,图像的表示是mat[y][x],这个搞了也挺久的,到处改(顺带一提,Python我用了个for x in,和后面的x变量命名重了,这个bug找的也真的久,写Python真的要注意变量范围,这比C++难多了)

5.多边形选取:最开始搞的ROI是矩形区域,做出来明显有问题,去网上学UI做了一个mask的操作,关于mask要注意区分3个图的坐标表示

6.其他细节:迭代事可能会爆值,结束后判255与0,中间判会增加误差;numpy中array用法不能和list等级,对于array, a[i][j] = [0,0,0]是错误写法,只能写成 a[i][j].all == 0; 对于list, a[i][j] == [0, 0, 0] 返回的是[True, True, True].

算法的局限:

1.背景图像选取应避免边缘截断,目标图像的背景色应和背景的颜色相近

2.使用混合梯度可以使边缘更加圆滑,但是可能会造成颜色变暗,论文后来进行了调色

3.选取图像本身有噪音或者色彩值比较极端经处理后缺陷会放大(网图有些看着正常,但实际颜色和肉眼观察不符,而且网图有很多也是合成的,要注意

原代码及成品:

python处理:

import cv2
import matplotlib.pyplot as plt
import numpy as np
import math
%matplotlib inline

def cv_show(name, img):
    cv2.imshow(name, img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

    
lsPointsChoose = []
tpPointsChoose = []
pointsCount = 0
count = 0
Y, X = 0, 0
pointsMax = 6
lenx, leny = 0, 0
x1, y1, = 0, 0
centerx, centery = 0, 0
flag = esc = False
img = cv2.imread(\'ren2.jpg\') #读取图像
dst = cv2.imread("ren1.jpg")

# 图像大小处理
h, w = dst.shape[:2]
# dst = cv2.resize(dst, (int(w*0.8), int(h*0.8)) )
img = cv2.resize(img, (int(w), int(h)) )

tmp = img.copy()
img2 = img.copy()
tmp3 = img.copy()
tmp2 = dst.copy()

fhand = open(\'data.txt\',\'w\')
cv2.namedWindow(\'getROI\')
cv2.setMouseCallback(\'getROI\',getROI)

cv2.namedWindow(\'background\')
cv2.imshow(\'background\', dst)
cv2.setMouseCallback(\'background\', getcenter)
while(1):
  cv2.imshow(\'getROI\',img)
  if cv2.waitKey(1)&0xFF==ord("e"): 
     cv2.destroyAllWindows()
     break
fhand.close()
main part
def isout(x, y):
    if (mask2[x][y][0] == 0) :
        return True
    if (mask2[x+1][y][0] == 0):
        return True
    if (mask2[x-1][y][0] == 0):
        return True
    if (mask2[x][y+1][0] == 0):
        return True
    if (mask2[x][y-1][0] == 0):
        return True
    return False
    
def handle(mat, x, y, lenx, leny, laparr):
        global fhand
        for x__ in laparr:
            fhand.write(str(x__))
            fhand.write(\' \')
        for i in range(y, leny+y):
            for j in range(x, x+lenx):
                fhand.write(str(mat[i][j])+\' \')
                    
def getLap(mat, x, y, lenx, leny, t):
    ans = list()
    u = 0
    print(\'lap\',centerx,centery)
    for i in range(y, y+leny):
        for j in range(x, lenx+x):
            if isout(i, j):
                pass
            else:
                u = (mat[i][j]*4 - mat[i][j-1] - mat[i][j+1] - mat[i-1][j] - mat[i+1][j])
#                 混合梯度:
#                 v = (t[i-y+centery][j-x+centerx]*4 - t[i-y+centery][j-1-x+centerx] - t[i-y+centery][j+1-x+centerx] - t[i-1-y+centery][j-x+centerx] - t[i+1-y+centery][j-x+centerx])
#                 if abs(v) > abs(u):
#                     u = v
#                 print(\'ccc\',u,v)
            ans.append(u)
    return ans


def display(x, y, lenx, leny):
    global X, Y
    X = x
    Y = y

    global tmp, tmp2, fhand, mask2, tmp3
    fhand.write(str(lenx))
    fhand.write(\' \')
    fhand.write(str(leny))
    fhand.write(\'\\n\')

    for i in range(y, y+leny):
        for j in range(x, lenx+x):
            fhand.write(str(mask2[i][j][0]) + \' \')    
            
    B,G,R = cv2.split(tmp)#imge   
    b,g,r=cv2.split(tmp2)#background
    
    B = getLap(B, x, y, lenx, leny, b)
    G = getLap(G, x, y, lenx, leny, g)
    R = getLap(R, x, y, lenx, leny, r)
#     print(\'display\',centerx, centery)
    
    handle(b, centerx, centery, lenx, leny, B)
    handle(g, centerx, centery, lenx, leny, G)
    handle(r, centerx, centery, lenx, leny, R)
    
the core of possion

C++迭代处理数据:

#include<bits/stdc++.h>
using namespace std;
vector <double> sandu[3], mat[3];
vector <int> mask;
int lenx, leny, size;
vector <bool> vis;

int fix(int x){
    //防止爆值
    if(x > 255)return 255;
    if(x < 0)return 0;
    return x;
}

bool isout(int x, int y){
    // bool fg = 1;
    int idx = x * lenx + y;
    // if(mat[0][idx] == 1 && mat[1][idx] == 1 && mat[2][idx] == 1)return 0;
    // return 1;
    
    if(mask[idx] == 0) return 1;
    
    int dir[5] = {-1,1,lenx,-lenx};
    for(int i = 0; i < 4; i++){
        // fg = 1;
        int nw = idx + dir[i];
        if(nw < 0 || nw >= size)continue;
        if(mask[idx] == 0)return 1;
    }
    return 0;
}

int main(){
    freopen("data.txt","r",stdin);
    freopen("result1.txt","w",stdout);
    
    cin>>lenx>>leny;
    size=lenx*leny;
    for(int i = 0; i < size; i++){
        int u; scanf("%d", &u); mask.push_back(u);
    }
    for(int t = 0; t < 3; t++){
        int u;
        for(int i = 1; i <= size; i++){
            scanf("%d", &u); sandu[t].push_back(u*1.0);
        }
        for(int i = 1; i <= size; i++){
            scanf("%d", &u); mat[t].push_back(u*1.0);
        }
    }
    for(int i = 0; i < leny; i++)
        for(int j = 0; j < lenx; j++){
            bool v = isout(i, j);
            vis.push_back(v);
            // if(v) printf("%d %d\\n",i,j);
        }
    int cnt=0;
    for(int t = 0; t < 3; t++){
        bool fg = 1;
        while(fg){
            fg = 0;cnt++;
            for(int i = 0; i < leny; i++)
                for(int j = 0; j < lenx; j++){
                    int idx = i * lenx + j;
                    if(vis[idx])continue;
                    double nw = (sandu[t][idx] + mat[t][idx-1] + mat[t][idx+1] + mat[t][idx-lenx] + mat[t][idx+lenx]) / 4;
                    // if(nw > 255) nw = 255;
                    // if(nw < 0) nw = 0;
                    if(abs(nw - mat[t][idx]) > 1e-4)fg = 1;
                    mat[t][idx] = nw;
                    
                }
        }
    }
    
    printf("[");
    for(int i = 0; i < leny; i++){
        printf("[");
        for(int j = 0; j < lenx; j++){ 
            int b = fix(int(mat[0][i*lenx+j])); 
            int g = fix(int(mat[1][i*lenx+j])); 
            int r = fix(int(mat[2][i*lenx+j])); 
            printf("[%d,%d,%d]", b, g, r);
            if(j != lenx - 1)printf(", ");
        }
        printf("]");
        if(i != leny - 1)printf(",\\n");
        else printf("\\n");
    }
    printf("]");
}
View Code

Python处理

def getans(a, b):
    global dst
    cnt = 0
    cnt2 = 0
    centerx, centery = a, b
    print(a,b)
    res = open("result.txt","r")
    w = res.read()
    res.close()
    w = eval(w)
    for i in range(centery, centery + leny):  
        for j in range(centerx, centerx + lenx):
            if not isout(Y+i-centery, X+j-centerx):
                dst[i][j] = w[i-centery][j-centerx]
                cnt2 += 1
            else:
                cnt += 1
    print(cnt,cnt2)
    cv_show(\'ret\',dst)
#     print(cnt, cnt2)
getans(centerx,centery)    
output image

成品:

 

以上是关于CG——Possion Image Editing的主要内容,如果未能解决你的问题,请参考以下文章

image-video editing with ffmpeg on Ubuntu

GLIDE: Towards Photorealistic Image Generation and Editing with Text-Guided Diffusion Models

OpenCV小项目:图像融合(泊松融合—Possion Blending)

scikit-FEM-例1-求解Possion边值问题

self.editing 与 self.tableView.editing 和 setEditing 的混淆

OVS+DPDK Datapath 包分类技术