c++ - quitar - Eliminar la marca de agua de una imagen usando opencv
quitar marca de agua app (2)
En primer lugar, tengo esta imagen y quiero crear una aplicación que pueda detectar imágenes como esta y eliminar el círculo (marca de agua).
int main(){
Mat im1,im2,im3,gray,gray2,result;
im2=imread(" (2).jpg");
namedWindow("x",CV_WINDOW_FREERATIO);
imshow("x",im2);
//converting it to gray
cvtColor(im2,gray,CV_BGR2GRAY);
// creating a new image that will have the cropped ellipse
Mat ElipseImg(im2.rows,im2.cols,CV_8UC1,Scalar(0,0,0));
//detecting the largest circle
GaussianBlur(gray,gray,Size(5,5),0);
vector<Vec3f> circles;
HoughCircles(gray,circles,CV_HOUGH_GRADIENT,1,gray.rows/8,100,100,100,0);
uchar x;
int measure=0;int id=0;
for(int i=0;i<circles.size();i++){
if(cvRound(circles[i][2])>measure && cvRound(circles[i][2])<1000){
measure=cvRound(circles[i][2]);
id=i;
}
}
Point center(cvRound(circles[id][0]),cvRound(circles[id][1]));
int radius=cvRound(circles[id][2]);
circle(im2,center,3,Scalar(0,255,0),-1,8,0);
circle(im2,center,radius,Scalar(0,255,0),2,8,0);
ellipse(ElipseImg,center,Size(radius,radius),0,0,360,Scalar(255,255,255),-1,8);
cout<<"center: "<<center<<" radius: "<<radius<<endl;
Mat res;
bitwise_and(gray,ElipseImg,result);
namedWindow("bitwise and",CV_WINDOW_FREERATIO);
imshow("bitwise and",result);
// trying to estimate the Intensity of the circle for the thresholding
x=result.at<uchar>(cvRound(circles[id][0]+30),cvRound(circles[id][1]));
cout<<(int)x;
//thresholding the output image
threshold(ElipseImg,ElipseImg,(int)x-10,250,CV_THRESH_BINARY);
namedWindow("threshold",CV_WINDOW_FREERATIO);
imshow("threshold",ElipseImg);
// making bitwise_or
bitwise_or(gray,ElipseImg,res);
namedWindow("bitwise or",CV_WINDOW_FREERATIO);
imshow("bitwise or",res);
waitKey(0);
}
Hasta ahora lo que hice es:
- Lo convierto a escala de grises
- Detecto el círculo más grande usando círculos hough y luego hago un círculo con el mismo radio en una nueva imagen
-
Este nuevo círculo con el escala de grises usando (
bitwise_and
) me da una imagen con solo ese círculo - Umbral de esa nueva imagen
-
bitwise_or
el resultado del umbral
Mi problema es que no apareció ningún texto negro en la línea blanca curva dentro de este círculo. Intenté eliminar el color usando los valores de píxeles en lugar del umbral, pero el problema es el mismo, ¿alguna solución o sugerencia?
No estoy seguro de si la siguiente solución es aceptable en su caso. Pero creo que funciona un poco mejor y no le importa la forma de la marca de agua.
-
Elimine los trazos con filtrado morfológico. Esto debería darte una imagen de fondo.
-
Calcule la imagen de diferencia: diferencia = fondo - inicial y umbral: binario = umbral (diferencia)
- Umbralice la imagen de fondo y extraiga la región oscura cubierta por la marca de agua
- Desde la imagen inicial, extraiga los píxeles dentro de la región de la marca de agua y ponga umbral a estos píxeles, luego péguelos en la imagen binaria anterior
Arriba hay una descripción aproximada. El siguiente código debería explicarlo mejor.
Mat im = [load the color image here];
Mat gr, bg, bw, dark;
cvtColor(im, gr, CV_BGR2GRAY);
// approximate the background
bg = gr.clone();
for (int r = 1; r < 5; r++)
{
Mat kernel2 = getStructuringElement(MORPH_ELLIPSE, Size(2*r+1, 2*r+1));
morphologyEx(bg, bg, CV_MOP_CLOSE, kernel2);
morphologyEx(bg, bg, CV_MOP_OPEN, kernel2);
}
// difference = background - initial
Mat dif = bg - gr;
// threshold the difference image so we get dark letters
threshold(dif, bw, 0, 255, CV_THRESH_BINARY_INV | CV_THRESH_OTSU);
// threshold the background image so we get dark region
threshold(bg, dark, 0, 255, CV_THRESH_BINARY_INV | CV_THRESH_OTSU);
// extract pixels in the dark region
vector<unsigned char> darkpix(countNonZero(dark));
int index = 0;
for (int r = 0; r < dark.rows; r++)
{
for (int c = 0; c < dark.cols; c++)
{
if (dark.at<unsigned char>(r, c))
{
darkpix[index++] = gr.at<unsigned char>(r, c);
}
}
}
// threshold the dark region so we get the darker pixels inside it
threshold(darkpix, darkpix, 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);
// paste the extracted darker pixels
index = 0;
for (int r = 0; r < dark.rows; r++)
{
for (int c = 0; c < dark.cols; c++)
{
if (dark.at<unsigned char>(r, c))
{
bw.at<unsigned char>(r, c) = darkpix[index++];
}
}
}
Una versión de Python de la de
# Import the necessary packages
import cv2
import numpy as np
def back_rm(filename):
# Load the image
img = cv2.imread(filename)
# Convert the image to grayscale
gr = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Make a copy of the grayscale image
bg = gr.copy()
# Apply morphological transformations
for i in range(5):
kernel2 = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,
(2 * i + 1, 2 * i + 1))
bg = cv2.morphologyEx(bg, cv2.MORPH_CLOSE, kernel2)
bg = cv2.morphologyEx(bg, cv2.MORPH_OPEN, kernel2)
# Subtract the grayscale image from its processed copy
dif = cv2.subtract(bg, gr)
# Apply thresholding
bw = cv2.threshold(dif, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]
dark = cv2.threshold(bg, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]
# Extract pixels in the dark region
darkpix = gr[np.where(dark > 0)]
# Threshold the dark region to get the darker pixels inside it
darkpix = cv2.threshold(darkpix, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
# Paste the extracted darker pixels in the watermark region
bw[np.where(dark > 0)] = darkpix.T
cv2.imwrite(''final.jpg'', bw)
back_rm(''watermark.jpg'')
Aquí esta el resultado final:
El tiempo de procesamiento es muy corto usando numpy
time python back_rm.py
real 0m0.391s
user 0m0.518s
sys 0m0.185s