Удаление длинных горизонтальных / вертикальных линий с краевого изображения с помощью OpenCV
Как я могу использовать стандартные фильтры обработки изображений (из OpenCV) для удаления длинных горизонтальных и вертикальных линий из изображения?
Изображения черно-белые, поэтому удаление означает просто закрашивание черным.
Иллюстрация:
В настоящее время я делаю это в Python, перебирая строки и столбцы пикселей и определяя диапазоны последовательных пикселей, удаляя те, которые длиннее, чем N пикселей. Тем не менее, это очень медленно по сравнению с библиотекой OpenCV, и если есть способ сделать то же самое с функциями OpenCV, это, вероятно, будет на несколько порядков быстрее.
Я полагаю, что это может быть сделано путем свертки с использованием ядра, представляющего собой ряд пикселей (для горизонтальных линий), но мне трудно определить точную операцию, которая бы сработала.
5 ответов
Если ваши линии действительно горизонтальные / вертикальные, попробуйте это
import cv2
import numpy as np
img = cv2.imread('c:/data/test.png')
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
linek = np.zeros((11,11),dtype=np.uint8)
linek[5,...]=1
x=cv2.morphologyEx(gray, cv2.MORPH_OPEN, linek ,iterations=1)
gray-=x
cv2.imshow('gray',gray)
cv2.waitKey(0)
результат
Вы можете обратиться к документации по морфологическим преобразованиям OpenCV для более подробной информации.
Чтобы удалить горизонтальные линии из изображения, вы можете использовать алгоритм обнаружения краев для обнаружения краев, а затем использовать преобразование Хафа в OpenCV для обнаружения линий и окрашивания их в белый цвет:
import cv2
import numpy as np
img = cv2.imread(img,0)
laplacian = cv2.Laplacian(img,cv2.CV_8UC1) # Laplacian Edge Detection
minLineLength = 900
maxLineGap = 100
lines = cv2.HoughLinesP(laplacian,1,np.pi/180,100,minLineLength,maxLineGap)
for line in lines:
for x1,y1,x2,y2 in line:
cv2.line(img,(x1,y1),(x2,y2),(255,255,255),1)
cv2.imwrite('Written_Back_Results.jpg',img)
Как долго это "долго". Длинные, как в, строки, которые занимают длину всего изображения, или просто длиннее, чем n
пиксели?
Если последнее, то вы могли бы просто использовать n+1
Икс n+1
Медиана или режим фильтра, и установите угловые коэффициенты на ноль, и вы получите желаемый эффект.
Если вы имеете в виду только строки, которые имеют ширину всего изображения, просто используйте memcmp()
работать со строкой данных и сравнивать ее с предварительно выделенным массивом нулей, длина которого равна длине строки. Если они совпадают, вы знаете, что у вас есть пустая строка, которая охватывает горизонтальную длину изображения, и эту строку можно удалить.
Это будет НАМНОГО быстрее, чем поэлементные сравнения, которые вы используете в настоящее время, и очень хорошо объяснено здесь:
Почему memcpy() и memmove() быстрее, чем приращение указателя?
Если вы хотите повторить ту же операцию для вертикальных линий, просто транспонируйте изображение и повторите операцию.
Я знаю, что это скорее подход уровня системной оптимизации, чем фильтр openCV, как вы и просили, но он выполняет работу быстро и безопасно. Вы можете ускорить вычисление еще больше, если вам удастся заставить изображение и ваш пустой массив быть выровненными в памяти в 32-битном формате.
Другой.
package com.test12;
import org.opencv.core.*;
import org.opencv.imgproc.Imgproc;
import org.opencv.imgcodecs.Imgcodecs;
public class ImageSubstrate {
static{ System.loadLibrary(Core.NATIVE_LIBRARY_NAME); }
public static void main(String[] args) {
Mat source = Imgcodecs.imread("src//data//bill.jpg");
Mat image_h = Mat.zeros(source.size(), CvType.CV_8UC1);
Mat image_v = Mat.zeros(source.size(), CvType.CV_8UC1);
Mat output = new Mat();
Core.bitwise_not(source, output);
Mat output_result = new Mat();
Mat kernel_h = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(20, 1));
Imgproc.morphologyEx(output, image_h, Imgproc.MORPH_OPEN, kernel_h);
Imgcodecs.imwrite("src//data//output.jpg", output);
Core.subtract(output, image_h, output_result);
Imgcodecs.imwrite("src//data//output_result.jpg", output_result);
Mat kernel_v = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(1, 20));
Imgproc.morphologyEx(output_result, image_v, Imgproc.MORPH_OPEN, kernel_v);
Mat output_result2 = new Mat();
Core.subtract(output_result, image_v, output_result2);
Imgcodecs.imwrite("src//data//output_result2.jpg", output_result2);
}
}
Это для javacv.
пакет com.test11;
import org.opencv.core.*;
import org.opencv.imgproc.Imgproc;
import org.opencv.imgcodecs.Imgcodecs;
public class GetVerticalOrHorizonalLines {
static{ System.loadLibrary(Core.NATIVE_LIBRARY_NAME); }
public static void main(String[] args) {
//Canny process before HoughLine Recognition
Mat source = Imgcodecs.imread("src//data//bill.jpg");
Mat gray = new Mat(source.rows(),source.cols(),CvType.CV_8UC1);
Imgproc.cvtColor(source, gray, Imgproc.COLOR_BGR2GRAY);
Mat binary = new Mat();
Imgproc.adaptiveThreshold(gray, binary, 255, Imgproc.ADAPTIVE_THRESH_MEAN_C, Imgproc.THRESH_BINARY, 15, -2);
Imgcodecs.imwrite("src//data//binary.jpg", binary);
Mat horizontal = binary.clone();
int horizontalsize = horizontal.cols() / 30;
int verticalsize = horizontal.rows() / 30;
Mat horizontal_element = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(horizontalsize,1));
//Mat element = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(3,3));
Imgcodecs.imwrite("src//data//horizontal_element.jpg", horizontal_element);
Mat Linek = Mat.zeros(source.size(), CvType.CV_8UC1);
//x = Imgproc.morphologyEx(gray, dst, op, kernel, anchor, iterations);
Imgproc.morphologyEx(gray, Linek,Imgproc.MORPH_BLACKHAT, horizontal_element);
Imgcodecs.imwrite("src//data//bill_RECT_Blackhat.jpg", Linek);
Mat vertical_element = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(1,verticalsize));
Imgcodecs.imwrite("src//data//vertical_element.jpg", vertical_element);
Mat Linek2 = Mat.zeros(source.size(), CvType.CV_8UC1);
//x = Imgproc.morphologyEx(gray, dst, op, kernel, anchor, iterations);
Imgproc.morphologyEx(gray, Linek2,Imgproc.MORPH_CLOSE, vertical_element);
Imgcodecs.imwrite("src//data//bill_RECT_Blackhat2.jpg", Linek2);
}
}