关系图关系图使用技巧
最编程
2024-07-07 16:07:09
...
一、relation-graph简介
一个Vue的关系图谱组件,使用非常方便
relation-graph官网(上面有文档介绍和案例展示)
二、使用步骤
引入relation-graph
npm install --save relation-graph
使用组件
<RelationGraph
ref="seeksRelationGraph"
:options="graphOptions"
:on-node-click="onNodeClick"
:on-line-click="onLineClick"
:on-node-expand="onNodeExpand"
/>
</div>
三、参数配置
1.Graph 图谱
配置图谱的一些默认样式,工具栏等
graphOptions: {
allowSwitchLineShape: true,
isMoveByParentNode:true,
disableLineClickEffect:true,
'layouts': [
// {
// 'label': '布局1',
// 'layoutName': 'center',
// 'layoutClassName': 'seeks-layout-center',
// useLayoutStyleOptions: true,
// 'defaultNodeWidth': '50',
// 'defaultNodeHeight': '50',
// defaultNodeBorderWidth: 0,
// defaultNodeColor: 'rgba(238, 178, 94, 1)',
// defaultLineShape: 1
// },
// {
// 'label': '布局2',
// 'layoutName': 'tree',
// 'layoutClassName': 'seeks-layout-center',
// useLayoutStyleOptions: true,
// 'from': 'top',
// 'defaultNodeWidth': '30',
// 'defaultNodeHeight': '100',
// 'defaultJunctionPoint': 'tb',
// 'defaultNodeShape': 1,
// 'defaultLineShape': 4,
// 'defaultNodeBorderWidth': 0,
// 'defaultLineColor': 'rgba(0, 186, 189, 1)',
// 'defaultNodeColor': 'rgba(0, 206, 209, 1)',
// 'min_per_width': 40,
// 'max_per_width': 70,
// 'min_per_height': 200
// },
{
'label': '布局3',
'layoutName': 'tree',
'layoutClassName': 'seeks-layout-center',
useLayoutStyleOptions: true,
hideNodeContentByZoom:true,
'from': 'left',
'defaultNodeWidth': '100',
'defaultNodeHeight': '30',
'defaultJunctionPoint': 'lr',
'defaultNodeShape': 1,
'defaultLineShape': 6,
'defaultNodeBorderWidth': 0,
'defaultLineColor': '#c0c0c0',
'defaultNodeColor': '#ffa00b',
'min_per_width': 200,
'max_per_width': 400,
'min_per_height': 40,
'max_per_height': 70,
'defaultExpandHolderPosition':'right',
'defaultLineWidth':3
}
],
defaultJunctionPoint: 'border'
// 这里可以参考"Graph 图谱"中的参数进行设置
}
参数具体参考文档,看你需要什么样式或者开始什么功能,按照文档上来配置,layouts里可以配置多种布局,具体看是否需要布局切换
2.Node 节点
nodes': [
{ 'id': 'a', 'text': 'a' },
{ 'id': 'b', 'text': 'b-固定数据展开/关闭' },
{ 'id': 'b1', 'text': 'b1' },
{ 'id': 'b1-1', 'text': 'b1-1' },
{ 'id': 'b1-2', 'text': 'b1-2' },
{ 'id': 'b1-3', 'text': 'b1-3' },
{ 'id': 'b1-4', 'text': 'b1-4' },
{ 'id': 'b1-5', 'text': 'b1-5' },
{ 'id': 'b1-6', 'text': 'b1-6' },
{ 'id': 'b2', 'text': 'b2' },
{ 'id': 'b2-1', 'text': 'b2-1' },
{ 'id': 'b2-2', 'text': 'b2-2' },
{ 'id': 'c', 'text': 'c-动态数据展开/关闭' },
{ 'id': 'c1', 'text': 'c1-动态获取子节点', expandHolderPosition: 'right', expanded: false, data: { isNeedLoadDataFromRemoteServer: true, childrenLoaded: false }},
{ 'id': 'c2', 'text': 'c2-动态获取子节点', expandHolderPosition: 'right', expanded: false, data: { isNeedLoadDataFromRemoteServer: true, childrenLoaded: false }},
{ 'id': 'c3', 'text': 'c3-动态获取子节点', expandHolderPosition: 'right', expanded: false, data: { isNeedLoadDataFromRemoteServer: true, childrenLoaded: false }}]
node 节点参数也按照文档上来配置,我这里是需要用到动态获取子节点的,动态获取子节点代码
onNodeExpand(node,e){
console.log('onNodeExpand:', node);
// 根据具体的业务需要决定是否需要从后台加载数据
if (!node.data.isNeedLoadDataFromRemoteServer) {
console.log('这个节点的子节点已经加载过了');
// this.$refs.seeksRelationGraph.refresh();
return;
}
// 判断是否已经动态加载数据了
if (node.data.childrenLoaded) {
console.log('这个节点的子节点已经加载过了');
// this.$refs.seeksRelationGraph.refresh();
return;
}
this.g_loading = true;
node.data.childrenLoaded = true;
this.loadChildNodesFromRemoteServer(node, new_data => {
this.g_loading = false;
this.$refs.seeksRelationGraph.getInstance().appendJsonData(new_data, (graphInstance) => {
// 这些写上当图谱初始化完成后需要执行的代码
});
});
}
3.Link 关系
links是指节点之间的关系(link),图谱会根据这些关系来生成线条(Line)
'lines': [
{ 'from': 'a', 'to': 'b' },
{ 'from': 'b', 'to': 'b1' },
{ 'from': 'b1', 'to': 'b1-1' },
{ 'from': 'b1', 'to': 'b1-2' },
{ 'from': 'b1', 'to': 'b1-3' },
{ 'from': 'b1', 'to': 'b1-4' },
{ 'from': 'b1', 'to': 'b1-5' },
{ 'from': 'b1', 'to': 'b1-6' },
{ 'from': 'b', 'to': 'b2' },
{ 'from': 'b2', 'to': 'b2-1' },
{ 'from': 'b2', 'to': 'b2-2' },
{ 'from': 'a', 'to': 'c' },
{ 'from': 'c', 'to': 'c1' },
{ 'from': 'c', 'to': 'c2' },
{ 'from': 'c', 'to': 'c3' }]
四、特殊处理
因为我这里需要用到点击节点展示该节点的祖宗和子孙关系,还有展示点击某个关系展示该关系的祖宗和子孙节点,需要实现on-node-click和on-line-click事件
//节点点击函数
onNodeClick(nodeObject, $event) {
console.log('onNodeClick:', nodeObject);
const allLinks = this.$refs.seeksRelationGraph.getLinks();
allLinks.forEach(link => { // 还原所有样式
link.relations.forEach(line => {
line.color = "#c0c0c0";
line.lineWidth = 3;
});
});
let fromNodeList = []
let toNodeList = []
this.getFromNode(allLinks,nodeObject,fromNodeList)
this.getToNode(allLinks,nodeObject,toNodeList)
// fromNodeList.forEach(item=>{
// console.log(item.fromNode.id + "->"+item.toNode.id)
// })
// toNodeList.forEach(item=>{
// console.log(item.fromNode.id + "->"+item.toNode.id)
// })
toNodeList.forEach(item=>{
allLinks.filter(link => (link.fromNode === item.fromNode && link.toNode === item.toNode)).forEach(link => {
console.log(link.fromNode)
link.relations.forEach(line => {
line.color = "#ffa00b"
line.lineWidth = 5;
});
});
})
fromNodeList.forEach(item=>{
allLinks.filter(link => (link.fromNode === item.fromNode && link.toNode === item.toNode)).forEach(link => {
console.log(link.fromNode)
link.relations.forEach(line => {
line.color = "#ffa00b"
line.lineWidth = 5;
});
});
})
// 让与{nodeObject}相关的所有连线高亮
// allLinks.filter(link => (link.fromNode === nodeObject || link.toNode === nodeObject)).forEach(link => {
// console.log(link.fromNode)
// link.relations.forEach(line => {
// console.log('line:', line);
// line.data.orignColor = line.color;
// line.data.orignFontColor = line.fontColor || line.color;
// line.data.orignLineWidth = line.lineWidth || 1;
// line.lineWidth = 3;
// });
// });
// // 有时候更改一些属性后,并不能马上同步到视图,这需要以下方法让视图强制根据数据同步到最新
this.$refs.seeksRelationGraph.getInstance().dataUpdated();
},
//获取祖宗节点(递归)
getFromNode(allLinks,node,fromNodeList){
let linkList = allLinks.filter(link => (link.toNode === node))
if(linkList.length > 0){
linkList.forEach(link =>{
fromNodeList.push({fromNode:link.fromNode,toNode:node})
this.getFromNode(allLinks,link.fromNode,fromNodeList)
})
}
},
//获取子孙节点(递归)
getToNode(allLinks,node,toNodeList){
let linkList = allLinks.filter(link => (link.fromNode === node))
if(linkList.length > 0){
linkList.forEach(link =>{
toNodeList.push({fromNode:node,toNode:link.toNode})
this.getToNode(allLinks,link.toNode,toNodeList)
})
}
},
//关系惦记函数
onLineClick(lineObject, linkObject, $event) {
console.log('onLineClick:', linkObject);
const allLinks = this.$refs.seeksRelationGraph.getLinks();
allLinks.forEach(link => { // 还原所有样式
link.relations.forEach(line => {
line.color = "#c0c0c0";
line.lineWidth = 3;
});
});
let fromNodeList = []
let toNodeList = []
this.getFromNode(allLinks,linkObject.fromNode,fromNodeList)
this.getToNode(allLinks,linkObject.toNode,toNodeList)
toNodeList.push({fromNode:linkObject.fromNode,toNode:linkObject.toNode})
fromNodeList.forEach(item=>{
console.log(item.fromNode.id + "->"+item.toNode.id)
})
toNodeList.forEach(item=>{
console.log(item.fromNode.id + "->"+item.toNode.id)
})
toNodeList.forEach(item=>{
allLinks.filter(link => (link.fromNode === item.fromNode && link.toNode === item.toNode)).forEach(link => {
link.relations.forEach(line => {
line.color = "#ffa00b"
line.lineWidth = 5;
});
});
})
fromNodeList.forEach(item=>{
allLinks.filter(link => (link.fromNode === item.fromNode && link.toNode === item.toNode)).forEach(link => {
console.log(link.fromNode)
link.relations.forEach(line => {
line.color = "#ffa00b"
line.lineWidth = 5;
});
});
})
this.$refs.seeksRelationGraph.getInstance().dataUpdated();
}
五、完整代码
<template>
<div v-loading="g_loading">
<div style="height:calc(100vh - 50px);">
<RelationGraph
ref="seeksRelationGraph"
:options="graphOptions"
:on-node-click="onNodeClick"
:on-line-click="onLineClick"
:on-node-expand="onNodeExpand"
/>
</div>
<el-button type="success" class="c-show-code-button">
<el-link
href="https://github.com/seeksdream/relation-graph/blob/master/examples/views/seeks-graph-docs/demo/Demo4AdvMultiLayout.vue"
target="_blank" style="color: #ffffff;">查看代码
</el-link>
</el-button>
<el-drawer
title="node option:"
direction="rtl"
size="50%"
custom-class="c-drawer-window"
:modal="false"
:visible.sync="isShowCodePanel"
:with-header="false"
>
<iframe src="/relation-graph-codes/Demo4Logo.html" width="100%" height="100%" frameborder="0" scrolling="auto"
style=""/>
</el-drawer>
</div>
</template>
<script>
// 如果您没有在main.js文件中使用Vue.use(RelationGraph); 就需要使用下面这一行代码来引入relation-graph
// import RelationGraph from 'relation-graph';
import test from './test.json'
export default {
name: 'Demo',
components: {},
data() {
return {
g_loading:false,
isShowCodePanel: false,
graphOptions: {
allowSwitchLineShape: true,
isMoveByParentNode:true,
disableLineClickEffect:true,
'layouts': [
// {
// 'label': '布局1',
// 'layoutName': 'center',
// 'layoutClassName': 'seeks-layout-center',
// useLayoutStyleOptions: true,
// 'defaultNodeWidth': '50',
// 'defaultNodeHeight': '50',
// defaultNodeBorderWidth: 0,
// defaultNodeColor: 'rgba(238, 178, 94, 1)',
// defaultLineShape: 1
// },
// {
// 'label': '布局2',
// 'layoutName': 'tree',
// 'layoutClassName': 'seeks-layout-center',
// useLayoutStyleOptions: true,
// 'from': 'top',
// 'defaultNodeWidth': '30',
// 'defaultNodeHeight': '100',
// 'defaultJunctionPoint': 'tb',
// 'defaultNodeShape': 1,
// 'defaultLineShape': 4,
// 'defaultNodeBorderWidth': 0,
// 'defaultLineColor': 'rgba(0, 186, 189, 1)',
// 'defaultNodeColor': 'rgba(0, 206, 209, 1)',
// 'min_per_width': 40,
// 'max_per_width': 70,
// 'min_per_height': 200
// },
{
'label': '布局3',
'layoutName': 'tree',
'layoutClassName': 'seeks-layout-center',
useLayoutStyleOptions: true,
hideNodeContentByZoom:true,
'from': 'left',
'defaultNodeWidth': '100',
'defaultNodeHeight': '30',
'defaultJunctionPoint': 'lr',
'defaultNodeShape': 1,
'defaultLineShape': 6,
'defaultNodeBorderWidth': 0,
'defaultLineColor': '#c0c0c0',
'defaultNodeColor': '#ffa00b',
'min_per_width': 200,
'max_per_width': 400,
'min_per_height': 40,
'max_per_height': 70,
'defaultExpandHolderPosition':'right',
'defaultLineWidth':3
}
],
defaultJunctionPoint: 'border'
// 这里可以参考"Graph 图谱"中的参数进行设置
}
};
},
mounted() {
// this.$notify({
// title: '提示:',
// message: '点击右侧工具栏中的"布局"按钮来切换',
// type: 'success',
// duration: 10000
// });
this.showSeeksGraph();
},
methods: {
showSeeksGraph() {
const __graph_json_data = {
'rootId': 'a',
'nodes': [
{ 'id': 'a', 'text': 'a' },
{ 'id': 'b', 'text': 'b-固定数据展开/关闭' },
{ 'id': 'b1', 'text': 'b1' },
{ 'id': 'b1-1', 'text': 'b1-1' },
{ 'id': 'b1-2', 'text': 'b1-2' },
{ 'id': 'b1-3', 'text': 'b1-3' },
{ 'id': 'b1-4', 'text': 'b1-4' },
{ 'id': 'b1-5', 'text': 'b1-5' },
{ 'id': 'b1-6', 'text': 'b1-6' },
{ 'id': 'b2', 'text': 'b2' },
{ 'id': 'b2-1', 'text': 'b2-1' },
{ 'id': 'b2-2', 'text': 'b2-2' },
{ 'id': 'c', 'text': 'c-动态数据展开/关闭' },
{ 'id': 'c1', 'text': 'c1-动态获取子节点', expandHolderPosition: 'right', expanded: false, data: { isNeedLoadDataFromRemoteServer: true, childrenLoaded: false }},
{ 'id': 'c2', 'text': 'c2-动态获取子节点', expandHolderPosition: 'right', expanded: false, data: { isNeedLoadDataFromRemoteServer: true, childrenLoaded: false }},
{ 'id': 'c3', 'text': 'c3-动态获取子节点', expandHolderPosition: 'right', expanded: false, data: { isNeedLoadDataFromRemoteServer: true, childrenLoaded: false }}],
'lines': [
{ 'from': 'a', 'to': 'b' },
{ 'from': 'b', 'to': 'b1' },
{ 'from': 'b1', 'to': 'b1-1' },
{ 'from': 'b1', 'to': 'b1-2' },
{ 'from': 'b1', 'to': 'b1-3' },
{ 'from': 'b1', 'to': 'b1-4' },
{ 'from': 'b1', 'to': 'b1-5' },
{ 'from': 'b1', 'to': 'b1-6' },
{ 'from': 'b', 'to': 'b2' },
{ 'from': 'b2', 'to': 'b2-1' },
{ 'from': 'b2', 'to': 'b2-2' },
{ 'from': 'a', 'to': 'c' },
{ 'from': 'c', 'to': 'c1' },
{ 'from': 'c', 'to': 'c2' },
{ 'from': 'c', 'to': 'c3' }]
}
// const __graph_json_data = test
this.$refs.seeksRelationGraph.setJsonData(__graph_json_data, (graphInstance) => {
// 这些写上当图谱初始化完成后需要执行的代码
// console.log(this.$refs.seeksRelationGraph.getInstance().getLinks())
});
},
onNodeClick(nodeObject, $event) {
console.log('onNodeClick:', nodeObject);
const allLinks = this.$refs.seeksRelationGraph.getLinks();
allLinks.forEach(link => { // 还原所有样式
link.relations.forEach(line => {
line.color = "#c0c0c0";
line.lineWidth = 3;
});
});
let fromNodeList = []
let toNodeList = []
this.getFromNode(allLinks,nodeObject,fromNodeList)
this.getToNode(allLinks,nodeObject,toNodeList)
// fromNodeList.forEach(item=>{
// console.log(item.fromNode.id + "->"+item.toNode.id)
// })
// toNodeList.forEach(item=>{
// console.log(item.fromNode.id + "->"+item.toNode.id)
// })
toNodeList.forEach(item=>{
allLinks.filter(link => (link.fromNode === item.fromNode && link.toNode === item.toNode)).forEach(link => {
console.log(link.fromNode)
link.relations.forEach(line => {
line.color = "#ffa00b"
line.lineWidth = 5;
});
});
})
fromNodeList.forEach(item=>{
allLinks.filter(link => (link.fromNode === item.fromNode && link.toNode === item.toNode)).forEach(link => {
console.log(link.fromNode)
link.relations.forEach(line => {
line.color = "#ffa00b"
line.lineWidth = 5;
});
});
})
// 让与{nodeObject}相关的所有连线高亮
// allLinks.filter(link => (link.fromNode === nodeObject || link.toNode === nodeObject)).forEach(link => {
// console.log(link.fromNode)
// link.relations.forEach(line => {
// console.log('line:', line);
// line.data.orignColor = line.color;
// line.data.orignFontColor = line.fontColor || line.color;
// line.data.orignLineWidth = line.lineWidth || 1;
// line.lineWidth = 3;
// });
// });
// // 有时候更改一些属性后,并不能马上同步到视图,这需要以下方法让视图强制根据数据同步到最新
this.$refs.seeksRelationGraph.getInstance().dataUpdated();
},
getFromNode(allLinks,node,fromNodeList){
let linkList = allLinks.filter(link => (link.toNode === node))
if(linkList.length > 0){
linkList.forEach(link =>{
fromNodeList.push({fromNode:link.fromNode,toNode:node})
this.getFromNode(allLinks,link.fromNode,fromNodeList)
})
}
},
getToNode(allLinks,node,toNodeList){
let linkList = allLinks.filter(link => (link.fromNode === node))
if(linkList.length > 0){
linkList.forEach(link =>{
toNodeList.push({fromNode:node,toNode:link.toNode})
this.getToNode(allLinks,link.toNode,toNodeList)
})
}
},
onLineClick(lineObject, linkObject, $event) {
console.log('onLineClick:', linkObject);
const allLinks = this.$refs.seeksRelationGraph.getLinks();
allLinks.forEach(link => { // 还原所有样式
link.relations.forEach(line => {
line.color = "#c0c0c0";
line.lineWidth = 3;
});
});
let fromNodeList = []
let toNodeList = []
this.getFromNode(allLinks,linkObject.fromNode,fromNodeList)
this.getToNode(allLinks,linkObject.toNode,toNodeList)
toNodeList.push({fromNode:linkObject.fromNode,toNode:linkObject.toNode})
fromNodeList.forEach(item=>{
console.log(item.fromNode.id + "->"+item.toNode.id)
})
toNodeList.forEach(item=>{
console.log(item.fromNode.id + "->"+item.toNode.id)
})
toNodeList.forEach(item=>{
allLinks.filter(link => (link.fromNode === item.fromNode && link.toNode === item.toNode)).forEach(link => {
link.relations.forEach(line => {
line.color = "#ffa00b"
line.lineWidth = 5;
});
});
})
fromNodeList.forEach(item=>{
allLinks.filter(link => (link.fromNode === item.fromNode && link.toNode === item.toNode)).forEach(link => {
console.log(link.fromNode)
link.relations.forEach(line => {
line.color = "#ffa00b"
line.lineWidth = 5;
});
});
})
this.$refs.seeksRelationGraph.getInstance().dataUpdated();
},
onNodeExpand(node,e){
console.log('onNodeExpand:', node);
// 根据具体的业务需要决定是否需要从后台加载数据
if (!node.data.isNeedLoadDataFromRemoteServer) {
console.log('这个节点的子节点已经加载过了');
// this.$refs.seeksRelationGraph.refresh();
return;
}
// 判断是否已经动态加载数据了
if (node.data.childrenLoaded) {
console.log('这个节点的子节点已经加载过了');
// this.$refs.seeksRelationGraph.refresh();
return;
}
this.g_loading = true;
node.data.childrenLoaded = true;
this.loadChildNodesFromRemoteServer(node, new_data => {
this.g_loading = false;
this.$refs.seeksRelationGraph.getInstance().appendJsonData(new_data, (graphInstance) => {
// 这些写上当图谱初始化完成后需要执行的代码
});
});
},
loadChildNodesFromRemoteServer(node, callback) {
setTimeout(function() {
const _new_json_data = {
nodes: [
{ id: node.id + '-child-1', text: node.id + '-的动态子节点1', width: 150 },
{ id: node.id + '-child-2', text: node.id + '-的动态子节点2', width: 150 },
{ id: node.id + '-child-3', text: node.id + '-的动态子节点3', width: 150 }
],
lines: [
{ from: node.id, to: node.id + '-child-1' },
{ from: node.id, to: node.id + '-child-2' },
{ from: node.id, to: node.id + '-child-3'}
]
};
callback(_new_json_data);
}, 1000);
}
}
};
</script>
<!--<style lang="scss">-->
<!--</style>-->
<!--<style lang="scss" scoped>-->
<!--</style>-->
六、运行结果
推荐阅读
-
智能交通的新征程:赢创力士创与图微电子达成战略合作伙伴关系
-
学习如何使用在线绘图网站文图:完整教程
-
14-傅里叶变换的代码实现-一、numpy实现傅里叶变换和逆傅里叶变换 1.numpy实现傅里叶变换numpy.fft.fft2实现傅里叶变换,返回一个复数数组(complex ndarray),也就是频谱图像numpy.fft.fftshift将零频率分量移到频谱中心(将左上角的低频区域,移到中心位置) 20*np.log(np.abs(fshift))设置频谱的范围。可以理解为,之前通过傅里叶变换得到复数的数组,是不能通过图像的方法展示出来的,需要转换为灰度图像(映射到[0,255]区间)需要注意的是1> 傅里叶得到低频、高频信息,针对低频、高频处理能够实现不同的目的2> 傅里叶过程是可逆的,图像经过傅里叶变换、逆傅里叶变换后,能够恢复到原始图像3> 在频域对图像进行处理,在频域的处理会反映在逆变换图像上 # 将绘制的图显示在窗口 %matplotlib qt5 import cv2 import numpy as np import matplotlib.pyplot as plt img = cv2.imread(r"image\lena.bmp",cv2.IMREAD_GRAYSCALE) # 傅里叶变换 f = np.fft.fft2(img) # 移动中心位置 fshift = np.fft.fftshift(f) # 调整值范围 result = 20*np.log(np.abs(fshift)) plt.subplot(1,2,1) plt.imshow(img,cmap=plt.cm.gray) plt.title("original") plt.axis("off") plt.subplot(1,2,2) plt.imshow(result,cmap=plt.cm.gray) plt.title("result") plt.axis("off") plt.show 傅里叶变换的频谱图像: 2.numpy实现逆傅里叶变换numpy.fft.ifft2实现逆傅里叶变换,返回一个复数数组(complex ndarray)numpy.fft.ifftshiftfftshift函数的逆函数,将中心位置的低频,重新移到左上角iimg = np.abs(逆傅里叶变化结果)设置值的范围,映射到[0,255]区间 # 将绘制的图显示在窗口 %matplotlib qt5 import cv2 import numpy as np import matplotlib.pyplot as plt img = cv2.imread(r"image\boat.bmp",cv2.IMREAD_GRAYSCALE) # 傅里叶变换 f = np.fft.fft2(img) fshift = np.fft.fftshift(f) # 逆傅里叶变换 ishift = np.fft.ifftshift(fshift) iimg = np.fft.ifft2(ishift) iimg = np.abs(iimg) plt.subplot(1,2,1) plt.imshow(img,cmap=plt.cm.gray) plt.title("original") plt.axis("off") plt.subplot(1,2,2) plt.imshow(iimg,cmap=plt.cm.gray) plt.title("iimg") plt.axis("off") plt.show 将一副图像,进行傅里叶变换和逆傅里叶变换后,进行对比(一样的) 实例:通过numpy实现高通滤波,保留图像的边缘信息 获取图像的形状rows,cols = img.shape获取图像的中心点crow,ccol = int(rows/2),int(cols/2)将频谱图像的中心区域(低频区域)设置为0(黑色)fshift[crow-30:crow+30,ccol-30:ccol+30] = 0 # 将绘制的图显示在窗口 %matplotlib qt5 import cv2 import numpy as np import matplotlib.pyplot as plt img = cv2.imread(r"image\boat.bmp",cv2.IMREAD_GRAYSCALE) # 傅里叶变换 f = np.fft.fft2(img) fshift = np.fft.fftshift(f) # 高通滤波 rows,cols = img.shape crow,ccol = int(rows/2),int(cols/2) fshift[crow-30:crow+30,ccol-30:ccol+30] = 0 # 逆傅里叶变换 ishift = np.fft.ifftshift(fshift) iimg = np.fft.ifft2(ishift) iimg = np.abs(iimg) plt.subplot(1,2,1) plt.imshow(img,cmap=plt.cm.gray) plt.title("original") plt.axis("off") plt.subplot(1,2,2) plt.imshow(iimg,cmap=plt.cm.gray) plt.title("iimg") plt.axis("off") plt.show 使用numpy实现高通滤波的实验结果: 二、opencv实现傅里叶变换和逆傅里叶变换 1.opencv实现傅里叶变换 返回结果 = cv2.dft(原始图像,转换标识)1> 返回结果:是双通道的,第一个通道是结果的实数部分,第二个通道是结果的虚数部分2> 原始图像:输入图像要首先转换成np.float32(img)格式3> 转换标识:flags = cv2.DFT_COMPLEX_OUTPUT,输出一个复数阵列numpy.fft.fftshift将零频率分量移到频谱中心(将左上角的低频区域,移到中心位置)调整频谱的范围,将上面频谱图像的复数数组,转换为可以显示的灰度图像(映射到[0,255]区间)返回值 = 20*np.log(cv2.magnitude(参数1,参数2))1> 参数1:浮点型X坐标值,也就是实部2> 参数2:浮点型Y坐标值,也就是虚部 # 将绘制的图显示在窗口 %matplotlib qt5 import cv2 import numpy as np import matplotlib.pyplot as plt img = cv2.imread(r"image\lena.bmp",cv2.IMREAD_GRAYSCALE) # 傅里叶变换 dft = cv2.dft(np.float32(img),flags = cv2.DFT_COMPLEX_OUTPUT) # 移动中心位置 dftShift = np.fft.fftshift(dft) # 调整频谱的范围 result = 20*np.log(cv2.magnitude(dftShift[:,:,0],dftShift[:,:,1])) plt.subplot(1,2,1) plt.imshow(img,cmap=plt.cm.gray) plt.title("original") plt.axis("off") plt.subplot(1,2,2) plt.imshow(result,cmap=plt.cm.gray) plt.title("result") plt.axis("off") plt.show 傅里叶变换的频谱图像: 2.opencv实现逆傅里叶变换返回结果 = cv2.idft(原始数据)1> 返回结果:取决于原始数据的类型和大小2> 原始数据:实数或者复数均可numpy.fft.ifftshiftfftshift函数的逆函数,将中心位置的低频,重新移到左上角调整频谱的范围,映射到[0,255]区间返回值 = cv2.magnitude(参数1,参数2)1> 参数1:浮点型X坐标值,也就是实部2> 参数2:浮点型Y坐标值,也就是虚部 # 将绘制的图显示在窗口 %matplotlib qt5 import cv2 import numpy as np import matplotlib.pyplot as plt img = cv2.imread(r"image\lena.bmp",cv2.IMREAD_GRAYSCALE) # 傅里叶变换 dft = cv2.dft(np.float32(img),flags = cv2.DFT_COMPLEX_OUTPUT) dftShift = np.fft.fftshift(dft) # 逆傅里叶变换 ishift = np.fft.ifftshift(dftShift) iimg = cv2.idft(ishift) iimg = cv2.magnitude(iimg[:,:,0],iimg[:,:,1]) plt.subplot(1,2,1) plt.imshow(img,cmap=plt.cm.gray) plt.title("original") plt.axis("off") plt.subplot(1,2,2) plt.imshow(iimg,cmap=plt.cm.gray) plt.title("inverse") plt.axis("off") plt.show 将一副图像,进行傅里叶变换和逆傅里叶变换后,进行对比(一样的) 实例:通过opencv实现低通滤波,模糊一副图像
-
使用Vue和Leaflet绘制平面图(第二部分)
-
效果图:七夕情人节微信红包最高额度能达到520元,是否可以使用红包封面的小细节来增加吸引力呢?
-
使用Python实现中国邮递员问题的图与网络相关方法
-
使用LiveCharts2创建笛卡尔积图并进行缩放和平移操作
-
人脸检测神器:Haar特征和积分图的快速计算技巧
-
使用HOME进行未来运动估计的热图输出
-
超赞的免费在线思维导图工具,支持离线使用且无烦人广告哦!