├── ReadME.pdf ├── result1.jpg ├── result2.jpg ├── result3.jpg ├── result4.jpg ├── result5.jpg ├── result6.jpg ├── source1.jpg ├── source2.jpg ├── source3.jpg ├── source4.jpg ├── source5.jpg ├── source6.jpg ├── target1.jpg ├── target2.jpg ├── target3.jpg ├── target4.jpg ├── target5.jpg ├── target6.jpg ├── Demo.m ├── .github └── FUNDING.yml ├── README.md ├── license.txt ├── PIE_Gui.m └── PIE.m /ReadME.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahmoudnafifi/Poisson-image-editing/HEAD/ReadME.pdf -------------------------------------------------------------------------------- /result1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahmoudnafifi/Poisson-image-editing/HEAD/result1.jpg -------------------------------------------------------------------------------- /result2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahmoudnafifi/Poisson-image-editing/HEAD/result2.jpg -------------------------------------------------------------------------------- /result3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahmoudnafifi/Poisson-image-editing/HEAD/result3.jpg -------------------------------------------------------------------------------- /result4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahmoudnafifi/Poisson-image-editing/HEAD/result4.jpg -------------------------------------------------------------------------------- /result5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahmoudnafifi/Poisson-image-editing/HEAD/result5.jpg -------------------------------------------------------------------------------- /result6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahmoudnafifi/Poisson-image-editing/HEAD/result6.jpg -------------------------------------------------------------------------------- /source1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahmoudnafifi/Poisson-image-editing/HEAD/source1.jpg -------------------------------------------------------------------------------- /source2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahmoudnafifi/Poisson-image-editing/HEAD/source2.jpg -------------------------------------------------------------------------------- /source3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahmoudnafifi/Poisson-image-editing/HEAD/source3.jpg -------------------------------------------------------------------------------- /source4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahmoudnafifi/Poisson-image-editing/HEAD/source4.jpg -------------------------------------------------------------------------------- /source5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahmoudnafifi/Poisson-image-editing/HEAD/source5.jpg -------------------------------------------------------------------------------- /source6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahmoudnafifi/Poisson-image-editing/HEAD/source6.jpg -------------------------------------------------------------------------------- /target1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahmoudnafifi/Poisson-image-editing/HEAD/target1.jpg -------------------------------------------------------------------------------- /target2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahmoudnafifi/Poisson-image-editing/HEAD/target2.jpg -------------------------------------------------------------------------------- /target3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahmoudnafifi/Poisson-image-editing/HEAD/target3.jpg -------------------------------------------------------------------------------- /target4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahmoudnafifi/Poisson-image-editing/HEAD/target4.jpg -------------------------------------------------------------------------------- /target5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahmoudnafifi/Poisson-image-editing/HEAD/target5.jpg -------------------------------------------------------------------------------- /target6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahmoudnafifi/Poisson-image-editing/HEAD/target6.jpg -------------------------------------------------------------------------------- /Demo.m: -------------------------------------------------------------------------------- 1 | % 2 | % T3 Demo code 3 | % 4 | source='source6.jpg'; 5 | target='target6.jpg'; 6 | result='result6.jpg'; 7 | 8 | I1 = imread(source); % SOURCE IMAGE 9 | I2 = imread(target); % DESTINATION IMAGE 10 | 11 | PIE_Gui(I1,I2,result,1,0); 12 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: MahmoudAfifi 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 13 | custom: https://www.paypal.com/paypalme/MahmoudAfifi 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Matlab implementation of: 2 | Pérez, Patrick, Michel Gangnet, and Andrew Blake. "Poisson image editing." ACM Transactions on Graphics (TOG). Vol. 22. No. 3. ACM, 2003. 3 | 4 | ![PIE](https://user-images.githubusercontent.com/37669469/113340138-802ee100-92f9-11eb-9f3d-3636cd80a528.jpg) 5 | 6 | Gradient domain is used instead of intensity of pixels in image cloning to blend two images by solving Poisson equations with a predefined boundary condition. Based on this idea, there are two options: 7 | 1- Seamless cloning 8 | 2- Mixing gradients 9 | For more information read Readme.pdf 10 | 11 | ### Get Started 12 | 13 | 1- Open Demo.m 14 | 15 | 2- Change the filenames accordingly; in the current demo we assume the source, target, and result images have the following filenames: 16 | ``` 17 | source='source_image.jpg'; 18 | target='target_image.jpg'; 19 | result='result_image.jpg'; 20 | ``` 21 | 3- Run Demo.m 22 | 23 | 24 | ### Related projects: 25 | 26 | [MPB](https://github.com/mahmoudnafifi/modified-Poisson-image-editing): A modified Poisson blending to reduce PIE bleeding artifacts by a simple two-stage blending approach. 27 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017, mahmoud afifi 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution 13 | * Neither the name of York University nor the names of its 14 | contributors may be used to endorse or promote products derived from this 15 | software without specific prior written permission. 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /PIE_Gui.m: -------------------------------------------------------------------------------- 1 | %% 2 | % Author: Michael S. Brown, York University 3 | % 4 | % Simple Matlab GUI for selection a Region of Interest from Image1, and 5 | % pasting this into Image2. 6 | % 7 | % It calls a function called: PossionImageIntegration() 8 | % Currently this function is just a dummy function adds the ROI and 9 | % Dest together. This should generate the PIE image. 10 | % 11 | % Main functions: PIE_Gui 12 | % - Call back functions: myButtonPressDown, myButtonPressUp, 13 | % myMouseMotion, myKeypress 14 | % 15 | function PIE_Gui(I1, I2,FileName,Method,Color) 16 | 17 | % 18 | % ------------------- SELECT SOURCE ROI ------------------ 19 | % 20 | disp('USAGE: select a polygon region by using left mouse clicks to draw the vertices'); 21 | disp(' right nouse click to finish - you can then drag the selected region around.'); 22 | disp(' When you have it where you want it, double click left to cut it and paste to the next image.'); 23 | 24 | h = figure('MenuBar', 'none', 'Toolbar', 'none'); % open window 25 | [BW, xi, yi] = roipoly(I1); % this returns a binary image with white (1) in the mask 26 | 27 | % extract mask (crop image) 28 | [r,c] = find(BW == 1); % find the max values 29 | maxH = max(r) - min(r); % extract the height 30 | maxW = max(c) - min(c); % extract the width 31 | SRC = imcrop(I1,[min(c) min(r) maxW maxH]); % crop the image in the RIO 32 | 33 | % crop mask - make the mask RGB (3 layers) 34 | Mc = zeros(size(SRC)); % make a copy of Ic 35 | Mc(:,:,1) = imcrop(BW,[min(c) min(r) maxW maxH]); 36 | Mc(:,:,2) = imcrop(BW,[min(c) min(r) maxW maxH]); 37 | Mc(:,:,3) = imcrop(BW,[min(c) min(r) maxW maxH]); 38 | 39 | % 40 | % NOW SELECT PLACE TO PASTE 41 | % 42 | imshow(I2); 43 | title('Click and drag region to desired location. Press any key to integrate, press q to quit'); 44 | lh = line(xi, yi, 'Marker','.','LineStyle','-', 'Color', 'r', 'LineWidth',2); 45 | 46 | % Set up units and callback functions 47 | set(h, 'Units', 'pixels'); 48 | set(h,'WindowButtonDownFcn',@myButtonPressDown); 49 | set(h,'WindowButtonUpFcn',@myButtonPressUp); 50 | set(h, 'WindowButtonMotionFcn', @myMouseMotion); 51 | set(h, 'KeyPressFcn', @myKeyPress); 52 | 53 | myData.xi = xi-min(xi); 54 | myData.yi = yi-min(yi); 55 | myData.SRC = SRC; 56 | myData.DEST = I2; 57 | myData.Mc=Mc; 58 | myData.pressDown = 0; 59 | myData.line = lh; 60 | myData.curX = -1; 61 | myData.curY = -1; 62 | myData.Method=Method; 63 | myData.Color=Color; 64 | myData.FileName=FileName; 65 | 66 | set(h, 'UserData', myData); 67 | 68 | return 69 | 70 | 71 | %% 72 | % When button is pressed, call this function 73 | % 74 | function myButtonPressDown(obj,event_obj) 75 | 76 | myData = get(obj, 'UserData'); % get the user data (variable name does not have to be "myData" 77 | myData.pressDown = 1; % set mouse press = true 78 | p = get(gca,'CurrentPoint'); % get current position of mouse on the image 79 | curX = p(1,1); % extract the X position (it's a floating point value) 80 | curY = p(1,2); % extract the Y positions 81 | myData.curX = curX; 82 | myData.curY = curY; 83 | set(myData.line,'XData', myData.xi+curX, 'YData', myData.yi+curY); 84 | 85 | % Save the myData variable back to the object 86 | set(obj, 'UserData', myData); 87 | return 88 | 89 | %% 90 | % When button is released, call this function 91 | % 92 | function myButtonPressUp(obj,event_obj) 93 | 94 | myData = get(obj, 'UserData'); % get the user data 95 | myData.pressDown = 0; % set mouse press to be false 96 | set(obj, 'UserData', myData); % set the uer data (i.e. record mouse is not longer being pressed) 97 | 98 | return 99 | 100 | %% 101 | % Called anytime the mouse is moved 102 | % 103 | function myMouseMotion(obj,event_obj) 104 | 105 | myData = get(obj, 'UserData'); % get the user data 106 | 107 | if (myData.pressDown == 1) % we are only interested if the mouse is down 108 | p = get(gca,'CurrentPoint'); % get the current point from the image 109 | curX = p(1,1); % extract the point from the strange matlab datastructure return by previous line of code 110 | curY = p(1,2); 111 | set(myData.line,'XData', myData.xi+curX, 'YData', myData.yi+curY); 112 | myData.curX = curX; 113 | myData.curY = curY; 114 | set(obj, 'UserData', myData); 115 | end 116 | return 117 | 118 | 119 | %% 120 | % Call when key any pressed any key 121 | % 122 | function myKeyPress(obj, event_obj) 123 | 124 | if (event_obj.Key == 'q') 125 | close(obj); 126 | return; 127 | end 128 | 129 | % Update the userdata in the object 130 | myData = get(obj, 'UserData'); 131 | if (myData.pressDown == 0) % if mouse is not pressed 132 | 133 | if (myData.curX == -1) 134 | disp('Select a location'); 135 | return; 136 | end 137 | 138 | % 139 | % Get the source and destination image 140 | % Compute a new image (SImage) where the source is translated to 141 | % the correct position based on the last mouse position. 142 | % 143 | % 144 | DEST = myData.DEST; 145 | SRC = myData.SRC; 146 | tx = round(myData.curX); 147 | ty = round(myData.curY); 148 | 149 | [hh ww depth] = size(SRC); 150 | 151 | %use only the ROI 152 | TRG(:,:,1)=DEST( ty:(ty+hh-1), tx:(tx+ww-1), 1 ); 153 | TRG(:,:,2)=DEST( ty:(ty+hh-1), tx:(tx+ww-1), 2 ); 154 | TRG(:,:,3)=DEST( ty:(ty+hh-1), tx:(tx+ww-1), 3 ); 155 | 156 | % SImage( ty:(ty+hh-1), tx:(tx+ww-1), 1 ) = SRC(:,:,1); 157 | % SImage( ty:(ty+hh-1), tx:(tx+ww-1), 2 ) = SRC(:,:,2); 158 | % SImage( ty:(ty+hh-1), tx:(tx+ww-1), 3 ) = SRC(:,:,3); 159 | 160 | 161 | Mc = rgb2gray(myData.Mc); 162 | Mc(1,:)=0; 163 | Mc(end,:)=0; 164 | Mc(:,1)=0; 165 | Mc(:,end)=0; 166 | se = strel('disk',5); 167 | Mc = imerode( Mc,se); 168 | % Call the PIE function. It will returned the integrated image 169 | newI = PIE( TRG,SRC,Mc,myData.Method,myData.Color); 170 | %reconstruct 171 | if size(newI,3)==1 172 | DEST=rgb2gray(DEST); 173 | DEST( ty:(ty+hh-1), tx:(tx+ww-1)) = newI(:,:); 174 | else 175 | DEST( ty:(ty+hh-1), tx:(tx+ww-1), 1 ) = newI(:,:,1); 176 | DEST( ty:(ty+hh-1), tx:(tx+ww-1), 2 ) = newI(:,:,2); 177 | DEST( ty:(ty+hh-1), tx:(tx+ww-1), 3 ) = newI(:,:,3); 178 | end 179 | %PossionImageIntegration(SImage, DEST, tx, ty, ww, hh); 180 | imshow(DEST); 181 | imwrite(DEST,myData.FileName); 182 | end 183 | 184 | return 185 | 186 | -------------------------------------------------------------------------------- /PIE.m: -------------------------------------------------------------------------------- 1 | function im_out = PIE( im_target,im_source,im_mask,m,c ) 2 | %% 3 | % Author: Mahmoud Afifi, York University 4 | % 5 | %PIE function: blends the source image with the target one based on the 6 | %boundary given as a BW mask using Poisson Image Editing (PIE) 7 | % -Usage- 8 | % im_out = PIE(targetImage,sourceImage,mask,0,0); %for seamless cloning 9 | % (true color) 10 | % im_out = PIE(targetImage,sourceImage,mask,1,0); %for mixing gradients 11 | % (true color) 12 | % im_out = PIE(targetImage,sourceImage,mask,0,1); %for seamless cloning 13 | % (grayscale) 14 | % im_out = PIE(targetImage,sourceImage,mask,1,1); %for mixing gradients 15 | % (grayscale) 16 | % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 17 | % Citation: 18 | % Pérez, Patrick, Michel Gangnet, and Andrew Blake. 19 | % "Poisson image editing." ACM Transactions on Graphics (TOG). Vol. 22. 20 | % No. 3. ACM, 2003. 21 | % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 22 | % -Inputs- 23 | % im_target: target image 24 | % im_source: source image 25 | % im_mask: mask image 26 | % m: 0 for seamless cloning (default), and 1 for mixing gradients. 27 | % c: 0 for true color source and target images (default), and 1 for 28 | % grayscale source and target images. 29 | % -Outputs- 30 | % im_out: output image after blending the source image with the source 31 | % image based on the given mask (uint8). 32 | 33 | %% 34 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 35 | %Initialization 36 | 37 | if nargin<3 38 | error('Please, use PIE(targetImage,sourceImage,mask)'); 39 | elseif nargin<4 40 | m=0; %use the default method (seamless cloning) 41 | c=0; %use the default image type (true color) 42 | elseif nargin<5 43 | c=0; %use the default image type (true color) 44 | end 45 | 46 | if size(im_target,1)~= size(im_source,1) || ... 47 | size(im_target,1)~= size(im_mask,1) || ... 48 | size(im_target,2)~= size(im_source,2) || ... 49 | size(im_target,2)~= size(im_mask,2) || ... 50 | size(im_target,3)~=size(im_source,3) 51 | error('Please, use images with the same size'); 52 | end 53 | 54 | %if the mask is not grayscale, convert it 55 | if size(im_mask,3)>1 56 | im_mask=rgb2gray(im_mask); 57 | end 58 | 59 | %convert source and target images to double for more precise computations 60 | im_target=double(im_target); 61 | im_source=double(im_source); 62 | 63 | %if we are working with true color, let m=3 otherwise, m=1 64 | if c==0 %true color images 65 | c=3; %for the next for loop 66 | else 67 | c=1; 68 | if size(im_source,3)>1 69 | im_source=rgb2gray(im_source); 70 | end 71 | if size(im_target,3)>1 72 | im_target=rgb2gray(im_target); 73 | end 74 | 75 | end 76 | 77 | %initially, output image = target image 78 | im_out=im_target; 79 | 80 | 81 | %create the laplacian mask for the second derivative of the source image 82 | laplacian_mask=[0 1 0; 1 -4 1; 0 1 0]; 83 | 84 | %normalize the mask image to assure that unknown pixels = 1 85 | im_mask=mat2gray(im_mask); 86 | 87 | %convert it to logical to ignore any fractions (soft masks) 88 | im_mask=im_mask==1; 89 | 90 | %find the number of unknown pixels based on the mask 91 | n=size(find(im_mask==1),1); 92 | 93 | %create look up table 94 | map=zeros(size(im_mask)); 95 | 96 | %loop through the mask image to initialize the look up table for mapping 97 | counter=0; 98 | for x=1:size(map,1) 99 | for y=1:size(map,2) 100 | if im_mask(x,y)==1 %is it unknow pixel? 101 | counter=counter+1; 102 | map(x,y)=counter; %map from (x,y) to the corresponding pixel 103 | %in the 1D vector 104 | end 105 | end 106 | end 107 | 108 | 109 | for i=1:c %for each color channel 110 | 111 | % loop through the mask image again to: 112 | %1- initialize the coefficient matrix 113 | %2- initialize the B vector 114 | 115 | %if the method is seamless cloning; so, intially put B= (-) laplacian of 116 | %im_source, 117 | %otherwise (mixing gradients), B= (-) max(laplacian of im_source, laplacian 118 | %of im_target) 119 | 120 | %create the coefficient matrix A 121 | 122 | %At most, there are 5 coefficients per row according to eq (3) 123 | %in the report 124 | coeff_num=5; 125 | 126 | %create the sparse matrix to save memory 127 | A=spalloc(n,n,n*coeff_num); 128 | 129 | %create the right hand side of the linear system of equations (AX=B) 130 | B=zeros(n,1); 131 | 132 | if m==1 % mixing gradients 133 | 134 | %create the gradient mask for the first derivative 135 | grad_mask_x=[-1 1]; 136 | grad_mask_y=[-1;1]; 137 | 138 | %get the first derivative of the target image 139 | g_x_target=conv2(im_target(:,:,i),grad_mask_x, 'same'); 140 | g_y_target=conv2(im_target(:,:,i),grad_mask_y, 'same'); 141 | g_mag_target=sqrt(g_x_target.^2+g_y_target.^2); 142 | 143 | %get the first derivative of the source image 144 | g_x_source=conv2(im_source(:,:,i),grad_mask_x, 'same'); 145 | g_y_source=conv2(im_source(:,:,i),grad_mask_y, 'same'); 146 | g_mag_source=sqrt(g_x_source.^2+g_y_source.^2); 147 | 148 | %work with 1-D 149 | g_mag_target=g_mag_target(:); 150 | g_mag_source=g_mag_source(:); 151 | 152 | %initialize the final gradient with the source gradient 153 | g_x_final=g_x_source(:); 154 | g_y_final=g_y_source(:); 155 | 156 | %if the gradient of the target image is larger than the gradient of 157 | %the source image, use the target's gradient instead 158 | g_x_final(abs(g_mag_target)>abs(g_mag_source))=... 159 | g_x_target(g_mag_target>g_mag_source); 160 | g_y_final(abs(g_mag_target)>abs(g_mag_source))=... 161 | g_y_target(g_mag_target>g_mag_source); 162 | 163 | %map to 2-D 164 | g_x_final=reshape(g_x_final,size(im_source,1),size(im_source,2)); 165 | g_y_final=reshape(g_y_final,size(im_source,1),size(im_source,2)); 166 | 167 | %get the final laplacian of the combination between the source and 168 | %target images lap=second deriv of x + second deriv of y 169 | lap=conv2(g_x_final,grad_mask_x, 'same'); 170 | lap=lap+conv2(g_y_final,grad_mask_y, 'same'); 171 | 172 | else 173 | %create the laplacian of the source image 174 | lap=conv2(im_source(:,:,i),laplacian_mask, 'same'); 175 | end 176 | counter=0; 177 | for x=1:size(map,1) 178 | for y=1:size(map,2) 179 | if im_mask(x,y)==1 180 | counter=counter+1; 181 | A(counter,counter)=4; %the diagonal represent the current pixel 182 | 183 | %check the boundary 184 | if im_mask(x-1,y)==0 %known left pixel 185 | B(counter)=im_target(x-1,y,i); %add it to B 186 | else %unknown boundary 187 | A(counter,map(x-1,y))=-1; %set its coefficient to -1 188 | end 189 | if im_mask(x+1,y)==0 %known right pixel 190 | B(counter)=B(counter)+im_target(x+1,y,i); %add it to B 191 | else %unknown boundary 192 | A(counter,map(x+1,y))=-1; %set its coefficient to -1 193 | end 194 | if im_mask(x,y-1)==0 %known bottom pixel 195 | B(counter)=B(counter)+im_target(x,y-1,i); %add it to B 196 | else %unknown boundary 197 | A(counter,map(x,y-1))=-1; %set its coefficient to -1 198 | end 199 | if im_mask(x,y+1)==0 %known top pixel 200 | B(counter)=B(counter)+im_target(x,y+1,i); %add it to B 201 | else %unknown boundary 202 | A(counter,map(x,y+1))=-1; %set its coefficient to -1 203 | end 204 | 205 | %update the B vector with the laplacian value 206 | 207 | B(counter)=B(counter)-lap(x,y); 208 | 209 | end 210 | end 211 | end 212 | 213 | %solve the linear system of equation 214 | X=A\B; 215 | 216 | 217 | %reshape X to restore the output image 218 | 219 | % counter=0; 220 | % for x=1:size(map,1) 221 | % for y=1:size(map,2) 222 | % if im_mask(x,y)==1 223 | % counter=counter+1; 224 | % im_out(x,y,i)=X(counter); 225 | % end 226 | % end 227 | % end 228 | 229 | 230 | for counter=1:length(X) 231 | [index_x,index_y]=find(map==counter); 232 | im_out(index_x,index_y,i)=X(counter); 233 | 234 | end 235 | 236 | 237 | %release all 238 | clear A B X lap_source lap_target g_mag_source g_mag_target 239 | end 240 | 241 | im_out=uint8(im_out); 242 | 243 | end 244 | 245 | --------------------------------------------------------------------------------